.net - 访问 Form 上的成员可能会导致运行时异常,因为它是 marshal-by-reference 类的字段

标签 .net runtime warnings marshalbyrefobject

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/

相关文章:

Java - 构建类路径和运行时类路径优先级中的相同类

.net - 当您运行 .NET 可执行文件(一步一步到程序加载和运行的点)时,究竟会发生什么?

c++ - 无法解决警告C6386

c - 不使用数组时会显示数组下标类型为 'char' 的警告

c# - 检测到无法访问的代码

c# - 读取音频文件时出错?

c# - C#中的默认方法参数

linux - 如何处理不匹配的共享对象的 "undefined symbol"错误

java - 如果您使用遗留库,如何避免 Java 中的未经检查的转换警告?

c# - .net Lock - 两个问题