C#XML序列化向后兼容性

jsi*_*r13 10 c# xml serialization backwards-compatibility xml-deserialization

以前,序列化/反序列化方法使用以下类型Item:

public class Item{}
Run Code Online (Sandbox Code Playgroud)

现在我有了一个名为ItemWrapperderived from Itemwith new property 的新类:

public class ItemWrapper : Item
{
    public string NewProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在我的序列化/反序列化方法使用该类型ItemWrapper.现在我已经破坏了向后兼容性.我无法加载任何Item在旧版本中保存的类型的XML文件.我认为应该在反序列化方法使用try/catch当它试图反序列化Item的ItemWrapper,然后在抓我会再尝试反序列化的Item.或者我可以通过xPath查看XML结构,如果没有ItemWrapper找到,我可以将其视为Item.这两种解决方案都让人感觉很烦,而且我确信有更好的方法来处理这种情况.有任何想法吗?

Kei*_*thS 2

好问题。首先,虽然通过派生扩展类很好地遵守了开放/关闭原则,但如果 Item 的所有使用者现在都使用 ItemWrapper,那么您在实现派生类时就没有节省太多精力。如果 ItemWrapper 现在是唯一正在使用的具体对象,则将其新属性与 Item 合并即可完成。

如果您需要保留这两个具体内容,则需要使用一些属性来修饰 ItemWrapper,以指示 XMLSerializer 应如何与 XML 字符串相互转换。有关 XML 属性的信息可以在此处找到。

我特别提醒您注意XmlTypeAttribute。这会装饰 ItemWrapper 类本身,并告诉 XmlSerializer 使用特定的命名空间和类型名称,而不是根据类名称自动生成它们。您可以使用它来使 ItemWrapper 与序列化 Item 创建的 XML 文件兼容,方法是声明 ItemWrapper 类应创建和使用标记为 的 XML 序列化<Item>。但是,如果 Item 仍然存在,则在尝试反序列化通过序列化 ItemWrapper 创建的文件时将会失败,因此此解决方案不向前兼容,因此,如果您没有可靠地处理序列化错误,则您的软件的早期版本,当给予更新的文件时,会无缘无故地死掉

因此,在序列化中实现某种版本控制方案通常是一个好主意。它可以像类型上的公共只读属性一样简单,可以使用 XmlAttribute 属性进行标记,告诉 XmlSerializer 将标记构造<Item>为<Item xmlVersion="1.0.0">. 如果您之前已完成此操作,则 ItemWrapper 可以覆盖该字段以返回“1.1.0”,从而允许 XML 文件轻松区分,从而允许您使用 XmlTextReader 检查不兼容的文件版本,并优雅地返回错误如果该文件是由更高版本的软件生成的。