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

Accepted answer
Score: 32

You are probably talking about warning CS1690, repro 28 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 27 method will work with a proxy of the Remotable 26 object. Building a proxy for a property, method 25 or event isn't much of a problem, just a 24 matter of creating a MethodTable that contains 23 the substitutes. Fields are a problem however, there's 22 nothing to 'hook'. For a MBRO, the JIT 21 compiler no longer generates code to access 20 the field directly, it injects a call to 19 a helper method built into the CLR, JIT_GetField32() in 18 this case.

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

The 6 workaround for CS1690 is simple, beyond 5 wrapping the field with a property, just 4 copy the field value in a local variable. Now 3 it is crystal clear that the code is working 2 with a copy and there is never a surprise 1 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
}
Score: 10

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

public class Remotable : MarshalByRefObject {
    public int field;
}

could 7 become

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

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

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

Score: 3

Or you can write:

var obj = new Remotable();

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

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

Score: 1

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

More Related questions