Tweaking object serialization
If you've ever used binary serialization in .NET, you may have been frustrated with getting it to do exactly what you want it to do. To start with, you need to mark the entire class with the Serializable attribute. Then you can suppress a given field from the serialization stream by using the NonSerialized attribute. This is really handy if you have a class member representing a database connection or some other object that is more than just a stream of bytes. So if you tell it not to serialize it (which is good), how do you recreate it when the object is deserialized?
If you implement the ISerializable interface, you get complete power over serialization. This requires two things to be done. First, you must add a constructor that takes two parameters (examples taken from MS article):
protected MyObject(SerializationInfo info, StreamingContext context)
{
n1 = info.GetInt32("i");
n2 = info.GetInt32("j");
str = info.GetString("k");
}
If you don't do this, none of your constructors are called, so any initialization you need won't be done. In this example, after you deserialized every class member, you could add a call to some method that connects to a database or invokes a Web service. The GetObjectData method takes the same parameters, and performs the reverse operations to save the data in the first place.
I had done this before for a simple class, but didn't want to implement it on a class with over ten members. Plus, if I added members later I'd have to update the constructor and GetObjectData code or the fields would be missed. I really just wanted my default constructor to run to handle initialization, but it wasn't possible. It turns out that there is an easy solution though.
If you implement the IDeserializationCallback interface, you have just one method to add: OnSerialization(). This gets invoked *after* the class is deserialized, and here you can run any initialization you want! It would make sense to run whatever code would otherwise be run by the constructor. Of course, don't duplicate code. Factor out your initialization code to a new private init() method, and call that same method from constructors and the OnSerialization method. Now you have the best of both worlds -- nearly free serialization/deserialization, with flexibility to handle special cases. Cool stuff!
Microsoft article: Object Serialization in .NET