我正在尝试使用旧版本的应用程序反序列化“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和其他可序列化的东西。在这些课程中,一切都是可序列化的。 另外,我没有任何支柱。
答案 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