在这种情况下,我使用.NET序列化了一些NetDataContractSerializer对象,并将其存储在数据库中,以便在应用程序中记住这些对象的状态。最近,我刚刚遇到了第一种情况,即某些属性和类型名称的代码重构导致该XML数据反序列化失败。
到目前为止,我已经为如何处理版本兼容性中断提出了两种不同的攻击计划,比如使用NetDataContractSerializer本身中可用的工具来控制反序列化或直接转换XML。从我的实验和研究来看,可以使用自定义SerializationBinder反序列化到另一种类型,而属性名称/类型的更改可以通过实现ISerializable或通过实现ISurrogateSelector和ISerializationSurrogate编写序列化代理来解决。不幸的是,这个首选的机制还没有出现,除非我可以以其他方式显示,否则使用代理在序列化数据的版本之间移动似乎在NetDataContractSerializer中是不可能的,这是由于一些无法解释的微软的设计决策。Microsoft的建议是在双方都使用相同的序列化,这完全违背了使用代理项来帮助类型名称更改或移动到不同的命名空间或程序集的目的。
要修复它,请使用相同的NetDataContractSerializer实例或使用兼容的SurrogateSelector初始化的另一个实例。
这一解释与MSDN文章有冲突,MSDN文章可以这样说,即使用自定义绑定器替代类型以及处理序列化结构中的其他更改。
在反序列化过程中,格式化程序看到已经设置了绑定器。当每个对象都要反序列化时,格式化程序调用绑定器的BindToType方法,将格式化程序想要反序列化的程序集名称和类型传递给它。此时,BindToType决定应该实际构造什么类型,并返回此类型。 注意,如果新类型通过可序列化的自定义属性使用简单的序列化,则原始类型和新类型必须具有相同的确切字段名和类型。但是,新版本的类型可以实现ISerializable接口,然后调用它的特殊构造函数,类型可以检查SerializationInfo对象中的值,并确定如何反序列化自身。
所以,要么我可以让NetDataContractSerializer将V1 XML反序列化为V1类型,要么我必须手动转换XML。如果有人能够证明NetDataContractSerializer的SerializationInfo在使用ISerializable或使用序列化代理时确实有效,这将是很好的,或者至少比微软的解释更好,否则我可能会发布一个新的问题来讨论在.NET中直接转换旧XML的最佳方法。
更新2011-08-16:经过一些试验,如果序列化的原始类型实现了ISerializable,那么ISerializable和序列化代理技术都可以正常工作,否则,如果类型只是使用可序列化属性,那么对象图中的每个字段似乎都丢失了一些额外属性形式的有价值的类型信息。
使用可序列化的属性的示例
<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
<_stable z:Id="2">Remains the same</_stable>
<_x003C_OldProperty_x003E_k__BackingField>23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>实现ISerialzable的示例
<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
<_stable z:Id="2" z:Type="System.String" z:Assembly="0" xmlns="">Remains the same</_stable>
<_x003C_OldProperty_x003E_k__BackingField z:Id="3" z:Type="System.Int32" z:Assembly="0" xmlns="">23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>当使用带有自定义绑定器的NetDataContractSerializer反序列化第一个示例时,更改类型,然后在该类型上实现ISerializable,或者提供代理选择器,它指定一个基本上满足ISerializalbe角色的序列化代理程序,那么您将在ISerializationSurrogate.SetObjectData方法中看到一个空的SerializationInfo。在第二个示例中处理xml时,SerializationInfo似乎得到了正确的信息,并且一切都如愿以偿。
我的结论是,NetDataContractSerializer为仅通过SerializableAttribute支持序列化的类型生成的默认XML与使用ISerializable或序列化代理技术的反序列化不兼容,因为缺少类型信息。因此,为了更好地利用NetDataContractSerializable,应该定制序列化,以确保XML中包含这种类型的信息,这样以后的反序列化就可以自定义,而无需手动转换源XML。
发布于 2011-08-16 13:24:57
是的,如果您使用序列化,您必须有一个深思熟虑的数据迁移路径。您提到的解决方案是我个人要做的,在代码中包含一个检查,这将反序列化。如果检测到旧版本,则执行一个小的转换,使其与新格式相匹配,并根据需要继续进行。一旦转换了所有数据,该代码就可以在将来的版本中过时。
https://stackoverflow.com/questions/7078856
复制相似问题