jpi*_*son 5 .net netdatacontractserializer iserializable
我有一种情况,我使用NetDataContractSerializer序列化一些.NET对象,并将XML存储在数据库中,以此来记住应用程序中这些对象的状态.最近我遇到了第一种情况,其中一些代码重构属性和类型名称导致无法反序列化此XML数据.
到目前为止,我已经提出了两种不同的攻击计划,用于处理版本兼容性中断,例如使用NetDataContractSerializer本身可用的工具来控制反序列化或直接转换XML.从我的实验和研究看来,可以使用自定义SerializationBinder将其反序列化为不同的类型,并且可以通过实现ISerializable或通过实现ISurrogateSelector和ISerializationSurrogate来编写序列化代理来解决属性名称/类型更改.不幸的是,这个首选机制还没有完成,除非我可以显示,否则看起来使用代理商在NetDataContractSerializer上无法在序列化数据的版本之间移动,这是由于微软的一些无法解释的设计决定.Microsoft提出的建议是在双方使用相同的序列化,这完全违背了使用代理的目的,以便在类型名称更改或移动到不同的命名空间或程序集中时提供帮助.
要修复它,请使用相同的NetDataContractSerializer实例或另一个也使用兼容的SurrogateSelector初始化的实例.
这个解释与MSDN文章冲突,该文章说明了如何使用自定义绑定器替换类型以及处理序列化结构中的其他更改.
在反序列化期间,格式化程序看到已设置了活页夹.当每个对象即将被反序列化时,格式化程序调用绑定器的BindToType方法,向其传递格式化程序要反序列化的程序集名称和类型.此时,BindToType决定实际构造的类型并返回此类型.
请注意,如果新类型通过Serializable自定义属性使用简单序列化,则原始类型和新类型必须具有相同的确切字段名称和类型.但是,该类型的新版本可以实现ISerializable接口,然后将调用其特殊构造函数,该类型可以检查SerializationInfo对象中的值并确定如何反序列化自身.
因此,要么我能够让NetDataContractSerializer将我的V1 XML反序列化为我的V2类型,要么我将不得不手动转换XML.如果有人能够证明NetDataContractSerializer的SerializationInfo确实在使用ISerializable或使用序列化代理时确实有效,或者至少提供比Microsoft给出的更好的解释,否则我可能会发布一个新问题来讨论最好的方法在.NET中直接转换旧的XML.
更新2011-08-16: 经过一些实验,似乎ISerializable和序列化代理技术都可以正常工作,如果序列化的原始类型实现ISerializable,否则如果类型只使用[Serializable]属性,它会出现在对象中的每个字段图形以额外属性的形式缺少一些有价值的类型信息.
使用[Serializable]属性的示例
<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>
Run Code Online (Sandbox Code Playgroud)
实现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>
Run Code Online (Sandbox Code Playgroud)
当使用带有自定义绑定器的NetDataContractSerializer反序列化第一个示例以更改类型,然后在该类型上实现ISerializable或提供指定基本上满足ISerializalbe角色的序列化代理的代理选择器时,您将在ISerializationSurrogate中看到一个空的SerializationInfo .SetObjectData方法.在第二个示例中处理xml时,SerializationInfo似乎可以获得正确的信息,并且按预期工作.
我的结论是NetDataContractSerializer为仅支持通过SerializableAttribute进行序列化的类型生成的默认XML与使用ISerializable或序列化代理技术的反序列化不兼容,因为缺少类型信息.因此,为了使NetDataContractSerializable更具未来性,可以自定义序列化以确保XML中包含此类型信息,以便可以自定义以后的反序列化,而无需手动转换源XML.
是的,如果您使用序列化,则必须有一个经过深思熟虑的数据迁移路径。您提到的解决方案是我个人会做的,包括在反序列化的代码中进行检查。如果检测到旧版本,请进行小的转换,使其与新格式匹配,然后根据需要继续。一旦所有数据都被转换,该代码可能会在未来的版本中被废弃。