2009-12-18

C# serialization container type pattern

The following pattern is not my invention, but I find it neat as an alternative to implementing ISerializable  and/or IDeserializationCallback (or related attributes) when using .NET binary serialization. Your reasons for doing this may be performance or backwards-compatible serialization.

This takes advantage of the fact that the binary serialization framework stores the type of each object, and so you don't have to know the type on deserialization.

Now, let MyData be the type we want to store:
  1. Do not mark MyData as [Serializable]. Instead,
  2. introduce the IMyDataStorage interface containing the single method ToMyData().
  3. Now, the first version of MyData's serialized format is introduced as the class (or struct) MyDataStorage1, implementing IMyDataStorage.
  4. Introduce the method IMyDataStorage MyData.ToMyDataStorage().
When serializing, do this:

// Create an instance of the newest version of MyDataStorage.
IMyDataStorage storage = myData.ToMyDataStorage();
// Now, store it using regular binary serialization
using (Stream stream = new ...)
{
    new BinaryFormatter.Serialize(stream, storage)
}

When deserializing, do this:

// Deserialize
IMyDataStorage storage = new BinaryFormatter.Deserialize(stream)
MyData myData = storage.ToMyData();

Now, when you need to change the serialized format, introduce MyDataStorage2, and upgrade the MyDataStorage1.ToMyData. Except for that, leave MyDataStorage1 unchanged.

When you decide an old format is obsolete, just delete your definition of the old serialized type (and handle the ensuing SerializationException!).

No comments: