NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Implement ISerializable

Having the existence of an interface imply the existence of a constructor is an unusual design pattern, but we felt that it was needed for several reasons. Originally, we had a SetObjectData method on the interface but, like any interface method it was public. Because this method is designed to replace the entire internal state of the object, we didn't feel that it was valid to continue to leave this as a public method. This left us in the state of having the existence of the interface imply the existence of either a method or a constructor. Because, by default, no constructor is ever run on the object, we felt that it was more consistent to have this method be a constructor. The system ignores any visibility restrictions on the constructor, so the developer is free to mark it internal, protected, or even private and thus prevent external users from calling it.

When GetObjectData is called during serialization, the developer is responsible for returning a SerializationInfo. A SerializationInfo is a PropertyBag containing the type of the object being serialized and name/object pairs for the values being serialized. This structure is passed back to a Formatter which emits the data out onto the wire in the method required by its particular format. Developers are free to serialize as few or as many fields as they feel are appropriate, but the data transmitted must be sufficient to reconstitute the entire state of the object. If the base object of the current class implements ISerializable, it is usually correct to call that object's ISerializable.GetObjectData and add any additional fields required for serializing the derived class to the returned SerializationInfo.

During deserialization (the call to the constructor), the developer receives a SerializationInfo which has been populated with the type of the object and the name/object pairs which were transmitted over the stream. From this information, the developer is responsible for completely reconstituting the state of the object. If the base class also implements ISerializable, the developer has the responsiblity for calling the base class' constructor. The serialization infrastructure will delay calling this constructor until the entire SerializationInfo has been completed. If the SerializationInfo which is transmitted references objects A, B, and C, the SerializationInfo passed to the constructor will have been populated with references to objects A, B, and C. However, we do not guarantee that any of the objects referenced by A, B, or C have been completed. This makes it unsafe to call any code on A,B,or C that might require objects which they reference. For some objects, this may include code as simple as GetHashCode(). If your code requires you to do any execution based on the value of data contained in the objects referenced, it is usually best to cache the SerializationInfo and then implement IDeserializationEventListener (detailed below).

using System;
using System.Serialization;

public class ISerializableExample : ISerializable {

    int i, j, k;
    RuntimeTypeHandle th;

    private ISerializableExample(SerializationInfo info, StreamingContext context) {
        //Restore our scalar values.
        i = si.GetValue("i").ToInt32();
        j = si.GetValue("j").ToInt32();
        k = si.GetValue("k").ToInt32();

        //Deserialize the type and then get the TypeHandle from that.
        Type t = (Type)(si.GetValue("TypeObj").ToObject());
        th = t.TypeHandle;
    }

    public SerializationInfo GetObjectData(SerializationInfo si, StreamingContext context) {
        //SerializationInfo is essentially a property bag.
        
        
        //Add our three scalar values;
        si.AddValue("i", i);
        si.AddValue("j", j);
        si.AddValue("k", k);
        
        //TypeHandles are pointers to internal data structures.  They can't
        //be serialized directly, but we can get the type object and serialize that.
        Type t = Type.GetTypeFromHandle(th);
        si.AddValue("TypeObj", t);
        return si;
    }
}