I have to work an an old application that used binaryFormatter to serialize application data into filestream (say in a file named "data.oldformat") without any optimizazion the main class has been marked with attribute
<serializable()>public MainClass
.......
end class
and the serialization code
dim b as new binaryformatter
b.serialize(mystream,mymainclass)
In an attempt to optimize the serialization/deserialization process I simply made the class implement the ISerializable interface and wrote some optimized serialization routines
<serializable()>public MainClass
implements ISerializable
.......
end class
The optimization works really well but I MUST find a way to reatrive the data inside the old files for backward compatibility.
How can I do that??
Pierluigi
C# 4.0 is nearly backwards compatible with previous versions but there are a few breaking changes. For most ordinary code you won't notice these breaking changes. For the new features in C# 4 you can check out the Wikipedia article which has quite a good summary with examples.
Hence, private variables are not serialized. You cannot serialize private members using XmlSerializer unless your class implements the interface IXmlSerializable.
A property setter is not required for serialization. However, if a property does not have a setter, the XML will not deserialize to an object.
stmax has an excellent answer, however I would implement it like this, which uses SerializationEntry.GetEnumerator()
instead of try/catch
. This way is cleaner and significantly faster.
public MainClass(SerializationInfo info, StreamingContext context) {
int version = 0;
foreach (SerializationEntry s in info)
{
if (s.Name == "version")
{
version = (int)s.Value;
break;
}
}
switch (version) {
case 0:
// deserialize "old format"
break;
case 1:
// deserialize "new format, version 1"
break;
default:
throw new NotSupportedException("version " + version + " is not supported.");
}
}
I would prefer a LINQ version using .FirstOrDefault(), but SerializationInfo does not implement IEnumerable - in face, weirdly enough, it doesn't even implement the old IEnumerable interface.
since you've already implemented the ISerializable interface, you've probably also already added the required constructor:
public MainClass(SerializationInfo info, StreamingContext context) {}
you can use the info-object passed to the constructor to retrieve data from the serialized file. by default (i.e. when no ISerializable is implemented), the fields names are used as identifiers during serialization. so if your old class had a field "int x" you can deserialize this using:
this.x = info.GetInt32("x");
for newer versions i normally add a "version" entry during serialization, like this:
public void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue("version", 1);
info.AddValue("othervalues", ...);
}
during deserialization you can check this version entry and deserialize accordingly:
public MainClass(SerializationInfo info, StreamingContext context) {
int version;
try {
version = info.GetInt32("version");
}
catch {
version = 0;
}
switch (version) {
case 0:
// deserialize "old format"
break;
case 1:
// deserialize "new format, version 1"
break;
default:
throw new NotSupportedException("version " + version + " is not supported.");
}
}
i haven't compiled that code, might contain typos.
hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With