views:

80

answers:

4

I've got a class that will undergo certain version changes over the course of time. The data from inside this class is serialized and deserialized as part of the startup of my application. The problem I have is if I update the class by adding more properties, and then start the application, the old data does not get loaded properly.
What I'm looking to do is override the deserialization step, I don't mind manually reconstructing the object from xml, as I have a version number stored and can use it to recursively update versions of the object.

Is there an interface I can implement, or an attribute I can set somewhere, to be able to do this?

If you can't think of a way to do what I want, are there alternatives? such as defaulting values for properties that may not exist in the version of the xml I am loading.

+4  A: 

Implement the IXmlSerializable interface.

SLaks
+1  A: 

If it is xml-serialization specifically you're talking about you should implement the IXmlSerializable interface. If it's binary serialization you could just tag the new members with the OptionalField-attribute.

You can read more here: http://msdn.microsoft.com/en-us/library/ms229752(VS.80).aspx

Patrik Hägne
+1  A: 

Typically for versioning, you can use the OptionalField attribute to newly added members that might cause compatibility problems. During serialization, if member was not serialized, this leaves members value as null rather than throwing the exception.

Also, take a look at IDeserializationCallback.OnDeserialization interface which allows you to customize your deserialization.

desigeek
A: 

You can implement the ISerializable interface and provide a constructor which takes a SerializationInfo and a StreamingContext object to gain a finegrain control of the serialization/deserialization process.

For example:

[Serializable]
public struct MyStruct: ISerializable
{
    private readonly int _x;
    private readonly int _y;

    // normal constructor
    public MyStruct(int x, int y) : this()
    {
        _x = x;
        _y = y;
    }

    // this constructor is used for deserialization
    public MyStruct(SerializationInfo info, StreamingContext text) : this()
    {
        _x = info.GetInt32("X");
        _y = info.GetInt32("Y");
    }

    public int X { get { return _x; } }
    public int Y { get { return _y; } }

    // this method is called during serialization
    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("X", X);
        info.AddValue("Z", Y);
    }
}
theburningmonk