我正在尝试了解如何通过“引用”分配给 C# 中的类字段。
我要考虑以下示例:
public class X
{
public X()
{
string example = "X";
new Y(ref example);
new Z(ref example);
System.Diagnostics.Debug.WriteLine(example);
}
}
public class Y
{
public Y( ref string example )
{
example += " (Updated By Y)";
}
}
public class Z
{
private string _Example;
public Z(ref string example)
{
this._Example = example;
this._Example += " (Updated By Z)";
}
}
var x = new X();
当运行上面的代码时,输出是:
X (Updated By Y)
而不是:
X (Updated By Y) (Updated By Z)
正如我所希望的那样。
似乎给一个字段赋一个“ref参数”就失去了引用。
有没有办法在分配给字段时保留引用?
最佳答案
正如其他人所指出的,您不能拥有“引用变量”类型的字段。但是,仅仅知道自己做不到可能并不令人满意;您可能还想首先知道为什么不,其次,如何绕过此限制。
之所以是因为只有三种可能:
1) 不允许引用类型的字段
2) 允许引用类型的不安全字段
3) 不要将临时存储池用于局部变量(又名“堆栈”)
假设我们允许 ref 类型的字段。那么你可以做
public ref int x;
void M()
{
int y = 123;
this.x = ref y;
}
现在可以在 M
完成后访问 y。这意味着要么我们在情况 (2) 中——访问 this.x
将崩溃并可怕地死去,因为 y 的存储不再存在——或者我们在情况 (3) 中,并且本地 y
存储在垃圾收集堆中,而不是临时内存池中。
我们喜欢将局部变量存储在临时池中的优化,即使它们是由 ref 传递的,我们讨厌这样的想法,即您可以在周围留下一个定时炸弹,这可能会使您的程序崩溃并在以后死亡。因此,选项一是:没有 ref 字段。
请注意,对于作为匿名函数的封闭变量的局部变量,我们选择选项 (3);这些局部变量不会分配到临时池之外。
这让我们想到了第二个问题:您如何解决这个问题?如果您想要 ref 字段的原因是为另一个变量创建 getter 和 setter,那是完全合法的:
sealed class Ref<T>
{
private readonly Func<T> getter;
private readonly Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value { get { return getter(); } set { setter(value); } }
}
...
Ref<int> x;
void M()
{
int y = 123;
x = new Ref<int>(()=>y, z=>{y=z;});
x.Value = 456;
Console.WriteLine(y); // 456 -- setting x.Value changes y.
}
好了。 y
存储在 gc 堆上,x
是一个具有获取和设置 y
能力的对象。
请注意,CLR 确实支持 ref 局部变量和 ref 返回方法,但 C# 不支持。也许假设的 C# future 版本将支持这些功能;我已经制作了它的原型(prototype)并且效果很好。但是,这在优先级列表中并不是真正的高,所以我不会抱太大希望。
更新:上一段中提到的功能最终在 C# 7 中真正实现了。但是,您仍然不能在字段中存储 ref。
关于c# - 如何将 "reference"分配给 C# 中的类字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2980463/