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).

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?