FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Dobbs M-Dev
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
March 04, 2003
Serializing Delegates

Richard Grimes
Serialization allows you to "suspend' objects, insert them into some permanent storage, and then resurrect them later in a totally different context
Serializing Delegates

There are two reasons for serialization: To allow you to store objects in some long-term storage, and to allow you to pass an object “by value” to another context (a context agile object). Typically, these two actions are unconnected, but it is interesting to experiment with serializable objects, as I’ll demonstrate in this newsletter.

A delegate is a "smart” function pointer. It holds information about the method to call, and if this is an instance method (rather than a static method), the delegate has information about the specific target object on which the method will be called. Delegate objects are actually containers and contain a linked list of individual delegate objects: When a delegate is invoked, each of the contained delegates is invoked in the order that they were placed in the container object. Compilers will create typed delegate classes derived from MulticastDelegate. This class is marked with [Serializable] and implements ISerializable through its base class Delegate, meaning that it supports custom serialization.

The reason why MulticastDelegate is serializable is so that you can pass a delegate between contexts, allowing a delegate to be invoked in a context other than the one where it was created. Typically, this is used in .NET remoting to allow callbacks to be performed between processes. But, as I have mentioned, serialization also means that such objects can be stored in permanent storage, as I’ll describe in a moment.

The Delegate class uses a private class named DelegateSerializationHolder to serialize information about the delegate class. This private class serializes information about the target objects held in the delegate and the methods to be invoked. If a delegate has a target object (that is, the method invoked is not static), the class of the target object must be serializable or marshal by reference. If the target object class is serializable, the object is serialized when the delegate is serialized, so the method will be executed in the same context as where the delegate is invoked. If the target object is marshal by reference, the reference will be passed to the context where the delegate is invoked, which means that the method will be invoked in the context where the target object was created. Clearly this requires that the target object is available when the delegate is invoked.

For example, if we have the following delegate and class:

public __delegate void Del();

[Serializable]
public __gc class X
{
String* str;
public:
X(String* s) : str(s) {}
void CallMe()
{
Console::WriteLine(S"you called {0}", str);
}
};
I can create a delegate and serialize it like this:
Del* d = new Del(new X(S"object one"), &X::CallMe);
FileStream* fs = File::Open(S"data.xml", FileMode::Create);
SoapFormatter* sf = new SoapFormatter;
sf->Serialize(fs, d);
fs->Close();
The file data.xml will contain all the information needed to invoke the delegate on the X target object:
FileStream* fs = File::Open(S"data.xml", FileMode::Open);
SoapFormatter* sf = new SoapFormatter;
Del* d = static_cast<Del*>(sf->Deserialize(fs));
fs->Close();
d();

The interesting thing about this code is that the target object could be created by a process days before the delegate is invoked. Indeed, the delegate could be invoked by a totally different process on a totally different machine, and this invocation could occur after the original process has shut down. Download the source code for this newsletter to see this mechanism in more detail.

Offhand I cannot think of any practical use for this (but I am sure someone will e-mail me a clever use for it), but clearly serialization allows you to "suspend objects, insert them into some permanent storage and then resurrect them later in a totally different context.


Richard Grimes speaks at conferences and writes extensively on .NET, COM, and COM+. He is the author of Developing Applications with Visual Studio .NET (Addison-Wesley, 2002). If you have comments about this topic, Richard can be reached at dotnet.dev@grimes.demon.co.uk.


RELATED ARTICLES
No Related Articles
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK