17 .net warnings runtime marshalbyrefobject
访问Form上的成员可能会导致运行时异常,因为它是marshal-by-reference类的字段
我知道这个警告是什么,知道如何解决它.
我的问题是为什么这会导致运行时错误?
Han*_*ant 28
你可能正在谈论警告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());
}
}
Run Code Online (Sandbox Code Playgroud)
在远程处理方案中,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
}
Run Code Online (Sandbox Code Playgroud)
除了@ hans-passant的建议外,我认为解决此警告的另一种有用方法是将您的字段变成属性。
public class Remotable : MarshalByRefObject {
public int field;
}
Run Code Online (Sandbox Code Playgroud)
可能成为
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
Run Code Online (Sandbox Code Playgroud)
并且您不再收到任何警告!(对此,汉斯·帕桑特(Hans Passant)已有出色的解释,请参阅他的文章)
显然,您不能总是更改正在使用的对象(例如:为您生成字段的WinForms),因此您可能必须回退到使用临时变量。