Friday, November 7, 2008

Serialization - ISerializable

Occasionally, you will design a type that requires complete control over how it is serialized and deserialized. The type must

1. Implement


public interface ISerializable {
void GetObjectData(SerializationInfo, StreamingContext context);
}


The GetObjectData method is responsible for determining what information is necessary to serialize the object and adds this information to the SerializationInfo object. The formatter now takes all of the values added to the SerializationInfo object and serializes each of them to the byte stream.

There are many destinations for a serialized set of objects: same process, different process on the same machine, different process on a different machine, and so on. In some rare situations, an object might want to know where it is going to be deserialized so that it can emit its state differently.

A method that receives a StreamingContext structure can examine the State property's bit flags to determine the source or destination of the objects being serialized/deserialized.

Note : Always call an overloaded AddValue methods to add serialization information for your type. If a field's type implements the ISerializable interface, don't call the GetObjectData on the field.

2. A constructor

If your class is sealed, I highly recommend that you declare this special constructor to be private.


protected Hashtable(
SerializationInfo info, StreamingContext context) {
}


Note: Instead of calling the various Get methods, the special constructor could instead call GetEnumerator, which returns a SerializationInfoEnumerator object that iterates through all the values contained within the SerializationInfo object. Each value enumerated is a System.Runtime.Serialization.SerializationEntry object.

A type may include fields that refer to other objects. When the special constructor is called, any fields that refer to other objects are guaranteed to be set correctly. That is, the fields' values will contain references to allocated objects. As these referenced objects may not have had their fields initialized yet, you should not execute any code in the special constructor that accesses any members on a referenced object.

If your type must access members (such as call methods) on a referenced type, then it is recommended that your type also implement the IDeserializationCallback interface's OnDeserialization method. When this method is called, all objects have had their fields set. But there's no way to tell what order multiple objects have their OnDeserialization method called. So, while the fields may be initialized, you still don't know if a referenced object is completely deserialized if that referenced object also implements the IDeserializationCallback interface.


Case 1 : Base class implements ISerializable

If your type also implements ISerializable, then your implementation of GetObjectData and your implementation of the special constructor must call the same functions in the base class in order for the object to be serialized and deserialized properly.

If your derived type doesn't have any additional fields and therefore has no special serialization/deserialization needs, then you do not have to implement ISerializable at all. Like all interface members, GetObjectData is virtual and will be called to properly serialize the object. In addition, the formatter treats the special constructor as "virtualized." That is, during deserialization, the formatter will check the type that it is trying to instantiate. If that type doesn't offer the special constructor, then the formatter will scan all of the base classes until it finds one that implements the special constructor.

Case 2 : Base class does not implement ISerializable

In this case, your class must manually serialize the base type's fields.



void ISerializable.GetObjectData(
SerializationInfo info, StreamingContext context) {

// Serialize the desired values for this class
info.AddValue("title", title);

// Get the set of serializable members for our class and base classes
Type thisType = this.GetType();
MemberInfo[] mi =
FormatterServices.GetSerializableMembers(thisType, context);

// Serialize the base class's fields to the info object
for (Int32 i = 0 ; i < mi.Length; i++) {
// Don't serialize fields for this class
if (mi[i].DeclaringType == thisType) continue;
info.AddValue(mi[i].Name, ((FieldInfo) mi[i]).GetValue(this));
}
}


Summary of http://msdn.microsoft.com/en-us/magazine/cc301767.aspx

No comments: