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

时间:2010-11-14 17:04:19

标签: .net runtime warnings marshalbyrefobject

  

访问Form上的成员可能会导致运行时异常,因为它   是一个按参考编组的字段

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

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

4 个答案:

答案 0 :(得分:25)

你可能正在谈论警告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即可。字段是一个问题,然而,没有什么可以“钩”。对于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
}

答案 1 :(得分:4)

除了来自@ hans-passant的建议之外,我认为修复此警告的另一个有用方法是将您的字段变为属性。

public class Remotable : MarshalByRefObject {
    public int field;
}

可能会成为

public class Remotable : MarshalByRefObject {
    public int field { get; set }
}

你不再收到任何警告! (Hans Passant对此已有一个极好的解释,见his post

显然,您不能总是改变您正在使用的对象(例如:为您生成字段的WinForms),因此您可能不得不回退使用临时变量。

答案 2 :(得分:0)

如果编组对象的另一侧已经死亡,它将抛出运行时错误,指出引用的对象不再存在。

答案 3 :(得分:0)

或者你可以写:

var obj = new Remotable();

Console.WriteLine(((int) obj.field).ToString());     // No warning

在这里,您自行负责该演员表(拆箱)。