在表格上访问成员可能会导致运行时例外

我知道这个警告是什么,并且知道如何解决。

我的问题是为什么这会导致运行时错误?

有帮助吗?

解决方案

您可能正在谈论警告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

在这里,您对该铸件(拆箱)承担自己的责任。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top