Accessing a member on Form may cause a runtime exception because it is a field of a marshal-by-reference class
我知道这个警告是什么,也知道如何解决。
我的问题是为什么这会导致运行时错误?
最佳答案
您可能在谈论警告 CS1690,重现代码:
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());
}
}
在远程场景中,Test.Run 方法将与 Remotable 对象的代理一起工作。为属性、方法或事件构建代理不是什么大问题,只需创建一个包含替代项的 MethodTable 即可。然而,字段是一个问题,没有什么可以“ Hook ”。对于 MBRO,JIT 编译器不再生成直接访问该字段的代码,而是注入(inject)对 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
}
关于.net - 访问 Form 上的成员可能会导致运行时异常,因为它是 marshal-by-reference 类的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29834600/