反序列化向后兼容性

时间:2011-03-21 18:26:22

标签: c# .net serialization

我正在尝试使用旧版本的应用程序反序列化“SomeClass”。我得到以下异常

  

System.Runtime.Serialization.SerializationException:ObjectManager发现无效的修正次数。这通常表示Formatter中存在问题。

当我序列化版本0.9 并尝试使用版本0.8反序列化时,反序列化会抛出异常。我认为OptionalField属性可以解决问题,但事实并非如此。

// Version 0.8
[Serializable()]
class Foo{
  Bar b;
} 

// Version 0.9
[Serializable()]
class Foo{
  Bar b;
  [OptionalField]
  Zoo z;
}

鉴于我无法更改版本0.8,我应该如何向Foo对象添加更多状态,以便以前的版本可以反序列化它们的任何内容?

任何指针都会非常感激。

更新1 Bar和Zoo是其他可序列化的类,包含Hashtables和其他可序列化的东西。在这些课程中,一切都是可序列化的。 另外,我没有任何支柱。

5 个答案:

答案 0 :(得分:27)

首先,永远不要将CLR的序列化功能用于任何类似于长期存储的功能。我们通常会犯这样的错误,将对象放在blob数据库字段中并在后面拍拍我们自己很聪明。然后CLR得到一个补丁或我们的程序集更改版本,你搞砸了。所以不要这样做。

如果您仍想这样做,管理问题的最佳方法是创建自己的SerializationBinder,如下所示:

public sealed class CustomBinder : SerializationBinder {

    public override Type BindToType(string assemblyName, string typeName) {

        Type typeToDeserialize = null;

        if (typeName.IndexOf("SomeType") != -1) {
            typeToDeserialize = typeof(Foo.Bar.Bax.NewType);
        }
        else if (typeName.IndexOf("SomeOtherType") != -1) {
            typeToDeserialize = typeof(Foo.Bar.Bax.SomeOtherNewType);
        }
        else {
            // ... etc
        }

        return typeToDeserialize;
    }
}

在反序列化之前设置您正在使用的格式化程序的Binder属性,以便它覆盖默认值。

请注意,我不是在这里提供插件解决方案,我建议如何解决问题。一旦你转换出你正在做的任何事情,调查其他序列化技术,如protobuf,或编写自己的。无论哪种方式,您都不应该依赖CLR来获得长期的序列化支持。

答案 1 :(得分:4)

如果每个版本的构造函数兼容(例如,两个版本都有无参数或Foo(Bar b)构造函数),则可以调用

BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = Formatters.FormatterAssemblyStyle.Simple;

在反序列化流之前。

答案 2 :(得分:3)

作为调查此问题的人员的建议“在为时已晚之前”......我强烈建议不要通过BinaryFormatter持续存在。对于同步的2个app域之间的瞬态传输是可以的,但这是关于IMO的。存在其他没有这些问题的序列化工具。就二进制而言,protobuf-net是一个非常合理的选择 - 允许添加/删除/重命名等没有痛苦。

答案 3 :(得分:2)

似乎这样做的一种方法是使用版本化对象,这样您就可以尝试使用最新版本反序列化对象。如果这不起作用,请退回一个版本,直到它成功。然后,在获得对象后,将其更新为对象的最新版本,并对没有数据的任何字段使用默认值。

答案 4 :(得分:0)

optional field属性应该已经完成​​了。您可以发布您尝试序列化的实际类。

你可以先试试这些事 -

structs转换为classes

尝试Soap Serialization而不是binary serilization