How to Define a Type That ImplementsISerializable When the Base Type Doesn’t Implement This Interface
As mentioned earlier, the ISerializable interface is extremely powerful, because it allows a type to take complete control over how instances of the type get serialized and deserialized. However, this power comes at a cost: The type is now responsible for serializing all of its base type’s fields as well. Serializing the base type’s fields is easy if the base type also implements the ISerializable inter- face; you just call the base type’s GetObjectData method.
However, someday, you may find yourself defining a type that needs to take control of its serial- ization, but whose base type does not implement the ISerializable interface. In this case, your derived class must manually serialize the base type’s fields by grabbing their values and adding them to the SerializationInfo collection. Then, in your special constructor, you will also have to get the values out of the collection and somehow set the base class’s fields. Doing all of this is easy (albeit
tedious) if the base class’s fields are public or protected, but it can be very difficult or impossible to do if the base class’s fields are private.
This following code shows how to properly implement ISerializable’s GetObjectData method
and its implied constructor so that the base type’s fields are serialized.
[Serializable] internal class Base {
protected String m_name = "Jeff";
public Base() { /* Make the type instantiable */ }
public Derived() { /* Make the type instantiable*/ }
// If this constructor didn't exist, we'd get a SerializationException
// This constructor should be protected if this class were not sealed [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] private Derived(SerializationInfo info, StreamingContext context) {
// Get the set of serializable members for our class and base classes Type baseType = this.GetType().BaseType;
MemberInfo[] mi = FormatterServices.GetSerializableMembers(baseType, context);
// Deserialize the base class's fields from the info object for (Int32 i = 0; i < mi.Length; i++) {
// Get the field and set it to the deserialized value FieldInfo fi = (FieldInfo)mi[i];
In this code, there is a base class, Base, which is marked only with the SerializableAttribute custom attribute. Derived from Base is Derived, which also is marked with the Serializable Attribute attribute and also implements the ISerializable interface. To make the situation more interesting, you’ll notice that both classes define a String field called m_name. When calling SerializationInfo’s AddValue method, you can’t add multiple values with the same name. The preceding code handles this situation by identifying each field by its class name prepended to the field’s name. For example, when the GetObjectData method calls AddValue to serialize Base’s m_name field, the name of the value is written as “Base+m_name.”