![](/img/trans.png)
[英]How do I reference a field in another class in a separate aspx page, using C#?
[英]How do I assign by “reference” to a class field in c#?
我试图了解如何通过“引用”分配给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(由Y更新)
并不是:
X(由Y更新)(由Z更新)
正如我所希望的。
似乎为字段分配“参考参数”会丢失参考。
分配给字段时,有什么方法可以保留引用?
谢谢。
正如其他人指出的那样,您不能具有“引用变量”类型的字段。 但是,仅仅知道自己做不到就可能不满意。 您可能还想知道第一,为什么不知道,第二,如何解决此限制。
原因是因为只有三种可能性:
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传递)的优化,并且我们讨厌这样的想法,即您可能会留下定时炸弹,这可能会使您的程序崩溃并在以后死掉。 因此,选项一是:没有引用字段。
请注意,对于作为匿名函数的封闭变量的局部变量,我们选择选项(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 locals和ref return方法,尽管C#不支持。 假设的C#未来版本可能会支持这些功能。 我已经制作了原型,并且效果很好。 但是,这在优先级列表上并不是很高,因此我没有希望。
更新:上面段落中提到的功能终于在C#7中实现了。但是,您仍然不能在字段中存储引用。
编号ref纯粹是一个调用约定。 您不能使用它来限定字段。 在Z中,_Example设置为传入的字符串引用的值。然后,您可以使用+ =为它分配一个新的字符串引用。 您永远不会分配示例,因此ref无效。
所需的唯一解决方法是拥有一个包含引用(此处为字符串)的共享的可变包装对象(数组或虚拟StringWrapper)。 通常,如果需要,可以找到更大的可变对象供类共享。
public class StringWrapper
{
public string s;
public StringWrapper(string s)
{
this.s = s;
}
public string ToString()
{
return s;
}
}
public class X
{
public X()
{
StringWrapper example = new StringWrapper("X");
new Z(example)
System.Diagnostics.Debug.WriteLine( example );
}
}
public class Z
{
private StringWrapper _Example;
public Z( StringWrapper example )
{
this._Example = example;
this._Example.s += " (Updated By Z)";
}
}
您忘了更新Z类中的引用:
public class Z {
private string _Example;
public Z(ref string example) {
example = this._Example += " (Updated By Z)";
}
}
输出:X(由Y更新)(由Z更新)
要记住的一点是,字符串的+ =运算符调用String.Concat()方法。 这将创建一个新的字符串对象,它不会更新字符串的值。 字符串对象是不可变的,字符串类没有任何可让您更改值的方法或字段。 与常规引用类型的默认行为有很大不同。
因此,如果使用字符串方法或运算符,则始终必须将返回值分配回变量。 这是很自然的语法,值类型的行为相同。 如果使用int而不是字符串,则代码将非常相似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.