|
Jason wonders about
some Great mysteries of the CLI
Also - why is [Serializable]
an attribute while MarshalByRefObject is a
base class? The arguments I've heard are pretty weak. As
Mike Woodring points
out, deriving from MBRO means inlining of methods has to be disabled.
And who derives from MBRO? EVERY SINGLE class in the Winforms
hierarchy.
As someone
who spent a good six months of his life inside the Remoting stack, I
certainly do have an opinion on this. At the beginning, I definitely thought the
same way. Why the heck didn't they implement yet another attribute for
designating an object as a remoteable one? This way, I could easily later flag
classes deeper down in my class hierarchy to be remoteable. And that's the very
answer as well. This just isn't possible.
Let's say
you have the following method: public void foo(bar x) { x.baz() }
And
you have an inheritance hierarchy of [System.Object]<-[bar].
In this case, the JIT could inline the call to baz().
If you'd use attributes to designate MarshalByRef
(or "proxyable") semantics, you could then extend the hierarchy: [System.Object]<-[bar]<-[foobar]
and flag foobar with this attribute. Bad thing. The JIT now must not inline
the call to baz().
The only possible way to
solve this is to have
[System.MarshalByRefObject]<-[bar] because
this way, the JIT knows right from the start not to inline the call to baz() and
everything will be fine.
Still - why does
every class in Winforms inherit from MBRO? Well, MBRO also conveys the point
that "it doesn't make sense to ever marshal me by value." This
basically means that the object is somehow bound to a resource on a single
machine, like an hWnd for example. So much for Windows Forms
[1].
I however also remember a discussion with
another speaker at one of the conference (not sure if it was Mike or Peter) in
which we were talking about our opinions that the name
"ProxyableObject" would have been better to convey the correct meaning.
Heck, it isn't about marshalling by reference - it's about proxying.
And no, I
don't think that these are the same things. A MarshalByRefObject would have to be proxyable but any
random proxyable object could just exist without any marshalling at all. I could
simply create a proxy (i.e. a custom RealProxy), flag
my class with a ProxyAttribute and see: I get a
proxy instead of a real object whenever I create a new instance of the
class.
So in fact,
ContextBoundObject should have been called
CustomProxiedObject. It's not about contexts - it's about an object
supplying its own proxy. Creating or checking contexts is just the work of one
very special kind of proxy. It could do many more things - like simply
intercepting method calls and providing for some AOP semantics.
[1] Weird
idea: maybe that's a good thing. You are normally supposed to check ctl.InvokeRequired (and if true, use ctl.Invoke() instead of directly manipulating the UI)
when working with multiple threads. You could write a simple, generic proxy
which you could use in front of any GUI control, and which would do this for you
automatically whenever you call any method or access any property. Hey, just
talking about getting rid of some
code.
|