如果您的方法实际上是:
public MyTestClass1 Method()
{
Test e = Test.test1;
/*some code*/
var omyTestClass1 = new MyTestClass1(ref e);
/*some code*/
e = Test.test2;
/*some code*/
e = Test.test3;
return omyTestClass1;
}
返回的值包含对已在堆栈上但现在不在堆栈上的值类型的引用。现在,如果您尝试访问该字段,您可以获得任何东西。
更糟糕的是,如果你写信给那个参考怎么办?如果该引用已存储在实际的调用堆栈中,而不是将其所有时间都花在寄存器中(并且我们可以安全地假设在一个类中有一个字段引用它的事实意味着它必须是那里),那么现在那里有什么?它可能是对对象的引用。它可能是一个返回地址。写入它可能会导致一些奇怪的 fandango-on-the-core 错误,很可能是在写入之后的一段时间,因此很难调试。
我们会失去一些我们拥有的基本保证。在您写入该值之后,几乎任何地方的任何代码都可能以某种奇怪的方式失败。
在这一点上值得注意的是,C++ 和 .NET 本身(也就是说,你可以在 .NET 中做的所有事情,包括一些你在 C# 中不能做的事情)都允许本地引用和 ref 的返回值不允许 ref字段。
最接近的方法是使用 lambdas 和匿名方法进行捕获。在这里,locals 不是存储在堆栈中,而是存储在堆中,以允许它们与生命捕获的 lambda 一样长(并在它们中的最后一个被收集时被收集)。您当然可以使用它来维护对对象中作为本地开始的内容的引用。
或者,您可以使用执行必要工作的类来包装值类型。例如,当我有足够类似的需求时,我使用了一个:
public sealed class SharedInt
{
private int _value;
/// <summary>Creates a new SharedInt with a value of zero.</summary>
public SharedInt(){}
/// <summary>Creates a new SharedInt.</summary>
/// <param name="value">The initial value of the object.</param>
public SharedInt(int value)
{
_value = value;
}
/// <summary>Returns the value of the SharedInt.</summary>
public int Value
{
get { return _value; }
}
/// <summary>Returns the value of the SharedInt.</summary>
/// <param name="ri">The SharedInt to cast.</param>
/// <returns>An integer of the same value as the SharedInt.</returns>
public static implicit operator int(SharedInt ri)
{
return ri._value;
}
/// <summary>Atomically increment the value of the SharedInt by one.</summary>
/// <returns>The new value.</returns>
public int Increment()
{
return Interlocked.Increment(ref _value);
}
/// <summary>Atomically decrement the value of the SharedInt by one.</summary>
/// <returns>The new value.</returns>
public int Decrement()
{
return Interlocked.Decrement(ref _value);
}
/// <summary>Atomically add a value to the SharedInt.</summary>
/// <param name="addend">The number to add to the SharedInt.</param>
/// <returns>The new value.</returns>
public int Add(int addend)
{
return Interlocked.Add(ref _value, addend);
}
/// <summary>Atomically replace the value of the SharedInt, returning the previous value.</summary>
/// <param name="value">The number to set the SharedInt to.</param>
/// <returns>The old value.</returns>
public int Exchange(int value)
{
return Interlocked.Exchange(ref _value, value);
}
/// <summary>Atomically subtract a value from the SharedInt.</summary>
/// <param name="subtrahend">The number to subtract from the SharedInt.</param>
/// <returns>The new value.</returns>
public int Subtract(int subtrahend)
{
return Interlocked.Add(ref _value, -subtrahend);
}
}
我需要一些原子性保证,你可能不需要,同样可能不需要一些你确实需要的东西,但它可以很好地作为一种能够处理int
不同类中相同值的方法。
如果你不介意每次都检查一个属性,你可以做一个更通用的版本。
public class TypedBox<T> where T : struct
{
public T Value;
}
公开一个字段有相当大的缺点(这就是为什么我们通常从不这样做),但大多数都不适用于这种情况(我们希望能够从外部完全操纵它),这意味着你甚至可以通过作为Value
一个ref
或out
参数。