ISerializable and backward compatibility

懵懂的女人 提交于 2019-11-30 20:38:34

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.

Just try the same thing you've been doing so far

BinaryFormatter b = new BinaryFormatter();
MainClass a = b.DeSerialize(mystream) as MainClass;

Implementing ISerializable didn't change your original class, basically you've just added some methods

When serializing your objects add an additional Version field (this shouldn't add too much overhead). Then in your GetObjectData method, try to retrieve the version field first and based on whether this exists or not (by catching the SerializationException) deserialize the old way or the new way. The old way will have just serialized all data so you should just be able to call Get... for all fields.

Your previous code should work. Do you get an exception? Try to use new constructor:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!