Friday, August 12, 2005

IXmlSerializable and IObjectReference

One way to serialize singleton or semi-singleton objects into XML. Not very nice, but working:

What I want to do is serialize a reference to a well-known global object, something like the ones derived from System.Type. I don't want the object to be serialized, I just want to transfer it's name to the other side where I'd use the name to find the global instance the reference should point to.

The secret is in using the IObjectReference interface. It can be used to have an object say "this is not me: there I am over there". The interface is used in object deserialization: if a deserializer retrieves an object that implements IObjectReference, it will call the object's GetRealObject method to get a reference the real object. So what we do is this: we add to our "global" object's class a string property called nameUsedForSerialization. It will be used only for serialization purposes (you may have already guessed it). We implement IXmlSerializable so that when the object is serialized, we'll serialize only its name. When it's deserialized, an empty object will be created that contains just the name. And then, when GetRealObject() is called, this name will be used to find the real object. Like this:

#region IXmlSerializable Members

private string nameUsedForSerialization;

public void WriteXml(System.Xml.XmlWriter writer)
{
string name = this.GetType().ToString() + "." + SomeInstanceName;
writer.WriteString(name);
}

public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}

public void ReadXml(System.Xml.XmlReader reader)
{
nameUsedForSerialization = reader.ReadString();
}

#endregion

#region IObjectReference Members

public object GetRealObject(StreamingContext context)
{
return MyUtilityClass.FindRealObject(nameUsedForSerialization);
}

#endregion