AddThis Social Bookmark Button

Print

Copying, Cloning, and Marshalling in .NET
Pages: 1, 2, 3

Listing 6: Playing around with inter-appdomain marshalling


using System;

// not [Serializable]
struct SimpleValueType
{
  public int a;
  public int b;
  public int c;
}

class MainMosdule
{
  static void Main()
  {
    // Create a "remote" appdomain
    AppDomain testDomain = 
                     AppDomain.CreateDomain( "testDomain");        
    MyRemoteableClass remoteObject = 
     (MyRemoteableClass)testDomain.CreateInstanceAndUnwrap(
                                        "test", 
                                        "MyRemoteableClass");

    // Initialize a SimpleValueType
    SimpleValueType x1 = new SimpleValueType();        
    x1.a = x1.b = x1.c = 7;

    // Try to send it across the wire 
    // (will fail unless [Serializable]!)
    remoteObject.DoSomethingWithSimpleValueType(x1);

    // Access the property X remotely        
    remoteObject.X = remoteObject.X+1;

    Console.WriteLine("{0}", remoteObject.X);
  }
}

The resulting exception looks something like this (long, boring stack trace omitted for brevity). But uncomment the [Serializable] attribute, and the program will run successfully.


Unhandled Exception: 
			System.Runtime.Serialization.SerializationException: 
        The type SimpleValueType in Assembly test, 
        Version=0.0.0.0, Culture=neutral, 
        PublicKeyToken=null is not marked as serializable.
 

To override this default MBV behavior, one can simply derive one's class from System.MarshalByRefObject -- and this is exactly what MyRemoteableClass does, as seen in Listing 7. (This is the same class referenced in Listing 6. We were skipping ahead a bit, but without at least one MBR object in the picture, there would be nothing to do the marshalling!)

Note that MarshalByRefObject is a base class, not an attribute, nor even an interface. This has a number of implications, the most obvious of which is that value-types cannot be made to marshal by reference (value-types in .NET cannot explicitly inherit from any base class other than System.ValueType). Perhaps the next most obvious implication is that you can't just revisit any old class to make it MBR -- .NET does not allow multiple inheritance of base classes, so you'll likely have to plan for that capability, from the ground up (or else end up writing a bunch of "MarshalByRefWrapper" classes, which isn't very fun).

Listing 7: A simple MBR-capable class (as seen in Listing 6)


class MyRemoteableClass : System.MarshalByRefObject
{
  private int x;

  public void DoSomethingWithSimpleValueType(SimpleValueType vt)
  { this.x = vt.a + vt.b + vt.c; }

  public int X
  {
    get { return this.x; }
    set { this.x = value; }
  }
}

Why is MarshalByRefObject a base class, rather than an interface or attribute? The easiest explanation is that MBR objects need quite a bit of boilerplate functionality (with regard to activation policies, lifetime services, etc.) that is best encapsulated in a base class, and re-used with implementation-inheritance. No other solution would allow us to create a MBR class with just a single line of code (let alone a single keyword).

More Fun With Marshalling: ref and out Parameters (Again)

Earlier, we saw that how the C# ref and out keywords affected the semantics of parameters passed to method calls. How do these keywords affect parameters marshalled between appdomains? In the intra-AppDomain case, we saw that using either ref or out was tantamount to passing a pointer to the argument (regardless of whether the argument was a reference-type or not).

But one cannot pass a pointer from one process to another -- let alone from one machine to another! Instead, one must think of marshalling as a form of messaging (which it is). Either way, the effect is largely the same. The C# code may look like an ordinary function call, but under the hood, the method's arguments are being packaged into an envelope and mailed away ... The ref keyword is an instruction to wait for a response, because the argument will travel both to and from the remote destination, along the remoting channel. Parameters with the out keyword (as well as return values) are only sent back, from callee to caller, along the channel. (Arguably, the IDL attribute keywords used to describe the same concepts in DCOM and RPC were more intuitive. These are listed in Table 2.) Just like DCOM (and RPC before it) it's the proxy objects on either side of the remoting channel that do all the dirty work.

Table 2: Analagous marshalling keywords in DCOM and .NET

RPC/DCOM keyword C# equivalent remoting keyword
[in] (default)
[in,out] ref
[out] out

Conclusion

Hopefully this article has shed some light on some basic aspects of .NET programming that should be quite straightforward -- moving copies of objects around from one place to another. But of course, nothing in modern computing is straightforward, anymore (especially if it involves remoting in any way). The .NET framework is a vast and complicated space to work in, but at the same time its design is vastly more intuitive for programmers than anything that came before.

We've examined everything from the differences between value-types and reference-types, the semantics of return-values, C#'s out and ref keywords, the ICloneable interface, the MemberwiseClone method, the special semantics of the framework's string class, and even a little bit of remoting and marshalling. Whew! Who knew that pushing bits around would be so hard?

References

"Passing Parameters" C# Programmer's Reference, MSDN Library

"Argument Passing ByVal and ByRef" Visual Basic Language Concepts, MSDN Library

"Nice Box. What's in It?" Eric Gunnerson, MSDN Library.

"Open the Box! Quick!" Eric Gunnerson, MSDN Library.

".NET Remoting: Design and Develop Seamless Distributed Applications for the Common Language Runtime" Dino Esposito, MSDN Magazine.


Return to ONDotnet.com