可ISerializable和向后兼容性

时间:2010-04-10 15:34:02

标签: .net backwards-compatibility binaryformatter iserializable

我必须使用一个旧的应用程序,它使用binaryFormatter将应用程序数据序列化到文件流中(比如在名为“data.oldformat”的文件中) 没有任何优化,主类已被标记为属性

<serializable()>public MainClass
....... 
end class

和序列化代码

dim b as new binaryformatter
b.serialize(mystream,mymainclass)

为了优化序列化/反序列化过程,我简单地让类实现了ISerializable接口并编写了一些优化的序列化例程

<serializable()>public MainClass
       implements ISerializable
....... 
end class

优化工作非常好但我必须找到一种方法来恢复旧文件中的数据以便向后兼容。

我该怎么做?

皮耶路易吉

5 个答案:

答案 0 :(得分:4)

因为您已经实现了ISerializable接口,所以您可能已经添加了所需的构造函数:

public MainClass(SerializationInfo info, StreamingContext context) {}

您可以使用传递给构造函数的info-object从序列化文件中检索数据。 默认情况下(即,当没有实现ISerializable时),字段名称在序列化期间用作标识符。因此,如果您的旧类具有字段“int x”,则可以使用以下方法对其进行反序列化:

this.x = info.GetInt32("x");

对于较新版本,我通常在序列化期间添加“版本”条目,如下所示:

public void GetObjectData(SerializationInfo info, StreamingContext context) {
  info.AddValue("version", 1);
  info.AddValue("othervalues", ...);
}

在反序列化期间,您可以检查此版本条目并相应地反序列化:

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.");
    }
}

我没有编译那段代码,可能包含错别字。

希望有所帮助。

答案 1 :(得分:4)

stmax 有一个很好的答案,但我会像这样实现它,它使用SerializationEntry.GetEnumerator()代替try/catch。这种方式更清晰,速度更快。

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.");
    }
}

我更喜欢使用.FirstOrDefault()的LINQ版本,但是SerializationInfo没有实现IEnumerable - 面对面,奇怪的是,它甚至没有实现旧的IEnumerable接口。

答案 2 :(得分:0)

尝试到目前为止你做的同样的事情

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

实现ISerializable并没有改变你的原始类,基本上你刚刚添加了一些方法

答案 3 :(得分:0)

序列化对象时,添加一个额外的Version字段(这不应该增加太多的开销)。然后在GetObjectData方法中,首先尝试检索版本字段,并根据是否存在(通过捕获SerializationException)反序列化旧方法或新方法。旧方法将序列化所有数据,因此您应该只能为所有字段调用Get ....

答案 4 :(得分:0)

您之前的代码应该有效。你有例外吗? 尝试使用新的构造函数:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)