在表格上访问成员可能会导致运行时例外
-
10-10-2019 - |
题
在表格上访问成员可能会导致运行时例外
我知道这个警告是什么,并且知道如何解决。
我的问题是为什么这会导致运行时错误?
解决方案
您可能正在谈论警告CS1690,repro代码:
public class Remotable : MarshalByRefObject {
public int field;
}
public class Test {
public static void Run() {
var obj = new Remotable();
// Warning CS1690:
Console.WriteLine(obj.field.ToString());
}
}
在远程方案中,测试方法将与远程对象的代理一起使用。为属性,方法或事件建立代理不是什么意思,只是创建包含替代品的方法的问题。字段是一个问题,但是没有什么可“挂钩”的。对于MBRO,JIT编译器不再生成代码直接访问该字段,它将在这种情况下为CLR jit_getfield32()内置的辅助方法注入呼叫。
该助手检查对象是否是代理,并使用远程管道来获取远程值。或者,如果不能直接访问该字段。但是,将toString()调用需要装箱。这是一个问题,拳击将价值与代理隔离。无法确保盒装值为 总是 远程值的准确副本。每当toString()方法使用该值来格式化字符串时,请再次调用Jit_getField32()。
CS1690的解决方法很简单,除了用属性包装字段之外,只需将字段值复制到本地变量中即可。现在很明显,该代码正在使用副本,而且永远不会感到惊讶,因此编译器不必发出警告。
public static void Run() {
var obj = new Remotable();
var value = obj.field;
Console.WriteLine(value.ToString()); // No warning
}
其他提示
除了 @Hans-Passant的建议外,我认为解决此警告的另一种有用方法是将您的领域变成属性。
public class Remotable : MarshalByRefObject {
public int field;
}
可能会变成
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
而且您将不再有任何警告! (Hans Passant已经对此有一个特别的解释,请参阅 他的帖子)
显然,您不能总是更改正在使用的对象(例如:为您生成的字段的Winforms),因此您可能必须退缩才能使用临时变量。
如果编组对象的另一侧已经死亡,则会丢弃运行时错误,说明不再存在引用对象。
或者您可以写:
var obj = new Remotable();
Console.WriteLine(((int) obj.field).ToString()); // No warning
在这里,您对该铸件(拆箱)承担自己的责任。
不隶属于 StackOverflow