Accessing a member on Form may cause a runtime exception because it is a field of a marshal-by-reference class

隐身守侯 提交于 2019-11-28 02:38:23

问题


Accessing a member on Form may cause a runtime exception because it is a field of a marshal-by-reference class

I know what this warning is and know how to solve it.

My question is why could this cause a runtime error?


回答1:


You are probably talking about warning CS1690, repro code:

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());
    }
}

In a remoting scenario, the Test.Run method will work with a proxy of the Remotable object. Building a proxy for a property, method or event isn't much of a problem, just a matter of creating a MethodTable that contains the substitutes. Fields are a problem however, there's nothing to 'hook'. For a MBRO, the JIT compiler no longer generates code to access the field directly, it injects a call to a helper method built into the CLR, JIT_GetField32() in this case.

That helper checks if the object is a proxy and uses the remoting plumbing to obtain the remote value if that's the case. Or just accesses the field directly if it isn't. Making the ToString() call however requires the value to be boxed. That's a problem, boxing isolates the value from the proxy. There is no way to ensure that the boxed value is always an accurate copy of the remoted value. Calling JIT_GetField32() again whenever the ToString() method uses the value to format the string isn't possible.

The workaround for CS1690 is simple, beyond wrapping the field with a property, just copy the field value in a local variable. Now it is crystal clear that the code is working with a copy and there is never a surprise so the compiler won't have to emit a warning.

public static void Run() {
    var obj = new Remotable();
    var value = obj.field;
    Console.WriteLine(value.ToString());     // No warning
}



回答2:


In addition to the suggestion from @hans-passant, I think another useful way to fix this warning is by turning your field into a property.

public class Remotable : MarshalByRefObject {
    public int field;
}

could become

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

and you no longer get any warnings! (Hans Passant already has an excelent explanation for this, see his post)

Obviously, you can not always alter the object you are working with (example: WinForms where the fields are generated for you) so you might have to fallback to using a temporary variable.




回答3:


If the other side of the marshalled object has died, it will throw a runtime error stating that the referenced object does not exist anymore.




回答4:


Or you can write:

var obj = new Remotable();

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

Here you take your own responsibility for that cast (unboxing).



来源:https://stackoverflow.com/questions/4178576/accessing-a-member-on-form-may-cause-a-runtime-exception-because-it-is-a-field-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!