【问题标题】:C# XML serialization backwards compatibilityC# XML 序列化向后兼容性
【发布时间】:2014-08-14 16:46:41
【问题描述】:

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

public class Item{}

现在我有一个名为 ItemWrapper 的新类,它从 Item 派生,并带有一个附加属性:

public class ItemWrapper : Item
{
    public string NewProperty { get; set; }
}

现在我的序列化/反序列化方法使用ItemWrapper 类型。现在我打破了向后兼容性。我无法加载保存在旧版本中的任何Item 类型的 XML 文件。当它尝试将Item 反序列化为ItemWrapper 时,我考虑在反序列化方法上放置一个try/catch,然后在catch 中我将尝试反序列化为Item。或者我可以通过 xPath 来查看 XML 结构,如果没有找到 ItemWrapper,我可以假设它为 Item。这两种解决方案都感觉很老套,我相信有更好的方法来处理这种情况。有什么想法吗?

【问题讨论】:

  • 你在项目上尝试过[XmlInclude(typeof(ItemWrapper))] 吗?
  • 这将解决我使用“项目”的问题。但是,我只是在继续序列化“ItemWrapper”。对我来说,问题是我有一个旧版本的 XML,它只有一个基于“项目”的 XML 结构。因此,当我反序列化这些旧 XML 时,它会引发异常。该属性对我没有帮助解决这个问题。

标签: c# xml serialization backwards-compatibility xml-deserialization


【解决方案1】:

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

如果您需要同时保留这两个结核,那么 ItemWrapper 需要用一些属性来装饰,以指示 XMLSerializer 应如何与 XML 字符串进行转换。有关 XML 属性的信息可以在 here 找到。

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

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

【讨论】:

  • Keith,我喜欢版本的想法,但不幸的是,“项目”没有这样做。同样由于其他原因,附加属性必须在派生类中,不能合并到基类中。我尝试使用您提供的 msdn 链接中的示例添加 XmlTypeAttribute,但没有成功。您还有其他使用此属性来完成您提到的内容的示例吗?感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2011-07-19
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多