Backward compatibility issue of Serialization

  • Thread starter Thread starter Dominic
  • Start date Start date
D

Dominic

Hi everybody,

I'm planning to use serialization to persist an object (and possibly
its child objects) in my application. However, I'm concerned about the
backward compatibility issue. I'm evaluating if we can easily resolve
this issue.

For example, I have a class MyClass consisting of 100 fields.

[Serializable]
public class MyClass
{
private int oldField1;
private int oldField2;
...
private int oldField100;
}

The basic serialization can be done simply by adding [Serializable]
attribute to the class. Suppose an object of this class has been
serialized to MyClass.bin using BinaryFormatter. Later, we have a new
version of this class, with the addition of newField101.

[Serializable]
public class MyClass
{
private int oldField1;
private int oldField2;
...
private int oldField100;
private int newField101;
}

If we use the basic deserialization to retrieve this object, the
following runtime exception will be thrown.

System.Runtime.Serialization.SerializationException: Possible Version
mismatch. Type MyClass has 101 members, number of members deserialized
is 100.

My question is how I can resolve this problem. I attempt to solve this
problem using the following approach.

[Serializable]
public class MyClass: ISerializable
{
private int oldField1;
private int oldField2;
...
private int oldField100;

protected MyClass(SerializationInfo info, StreamingContext context)
{
oldField1 = info.GetInt32("oldField1");
oldField2 = info.GetInt32("oldField2");
...
oldField3 = info.GetInt32("oldField100");

if (info.MemberCount == 100)
newField101 = 0;
else
newField101 = info.GetInt32("newField101");
}
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("oldField1", oldField1);
info.AddValue("oldField2", oldField2);
...
info.AddValue("oldField100", oldField100);
info.AddValue("newField100", newField101);

}
}

Does the above approach always solve the backward compatibility issue
of (de-)serialization?

Even if it does, it is a hassle that I need to list all 100 fields (or
101 fields) in the MyClass constructor and GetObjectData. Is there an
easier way to achieve backward compatibility?

Even if the class structure is not changed, do you think that a new
version of .NET framework will create similar compatibility problem?

Thanks
Dominic
 
So you have two things to worry about:
1. MyClass is going to change
2. MS is going to change the serialization format

1. Don't change MyClass at all, instead derive a new type from MyClass and use
that to add new fields. If you still want your application to return MyNewClass
types, then you can use a SerializationBinder to map instances of MyClass in the
stream to MyNewClass. There are many ways to control this entire process, and
some are more scalable/complex versus easy/quick to implement.
2. MS isn't going to change the format. If they do, the BinaryFormatter should
be able to handle both old and new formats.

What I would be worried about is contained in my blog entry:
http://weblogs.asp.net/justin_rogers/archive/2004/02/02/66508.aspx

Check that out and figure if you still want to use the BinaryFormatter


--
Justin Rogers
DigiTec Web Consultants, LLC.
Blog: http://weblogs.asp.net/justin_rogers


Dominic said:
Hi everybody,

I'm planning to use serialization to persist an object (and possibly
its child objects) in my application. However, I'm concerned about the
backward compatibility issue. I'm evaluating if we can easily resolve
this issue.

For example, I have a class MyClass consisting of 100 fields.

[Serializable]
public class MyClass
{
private int oldField1;
private int oldField2;
...
private int oldField100;
}

The basic serialization can be done simply by adding [Serializable]
attribute to the class. Suppose an object of this class has been
serialized to MyClass.bin using BinaryFormatter. Later, we have a new
version of this class, with the addition of newField101.

[Serializable]
public class MyClass
{
private int oldField1;
private int oldField2;
...
private int oldField100;
private int newField101;
}

If we use the basic deserialization to retrieve this object, the
following runtime exception will be thrown.

System.Runtime.Serialization.SerializationException: Possible Version
mismatch. Type MyClass has 101 members, number of members deserialized
is 100.

My question is how I can resolve this problem. I attempt to solve this
problem using the following approach.

[Serializable]
public class MyClass: ISerializable
{
private int oldField1;
private int oldField2;
...
private int oldField100;

protected MyClass(SerializationInfo info, StreamingContext context)
{
oldField1 = info.GetInt32("oldField1");
oldField2 = info.GetInt32("oldField2");
...
oldField3 = info.GetInt32("oldField100");

if (info.MemberCount == 100)
newField101 = 0;
else
newField101 = info.GetInt32("newField101");
}
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
info.AddValue("oldField1", oldField1);
info.AddValue("oldField2", oldField2);
...
info.AddValue("oldField100", oldField100);
info.AddValue("newField100", newField101);

}
}

Does the above approach always solve the backward compatibility issue
of (de-)serialization?

Even if it does, it is a hassle that I need to list all 100 fields (or
101 fields) in the MyClass constructor and GetObjectData. Is there an
easier way to achieve backward compatibility?

Even if the class structure is not changed, do you think that a new
version of .NET framework will create similar compatibility problem?

Thanks
Dominic
 
Back
Top