C# XML 序列化向后兼容性

问题描述 投票:0回答:2

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

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
。这两种解决方案都感觉很笨拙,我确信有更好的方法来处理这种情况。有什么想法吗?

c# xml serialization backwards-compatibility xml-deserialization
2个回答
2
投票

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

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

我特别提请您注意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 检查不兼容的文件版本,并优雅地返回错误如果该文件是由更高版本的软件生成的。
    


0
投票
但是,我只是继续序列化“ItemWrapper”。

保留
Item

成员,但将其更改为在序列化/反序列化期间执行您想要的操作。这假设您的代码不再使用它;它仅用于序列化:

// "Item MyItem" is what you had in old version.
// This member is not used in new code; exists only for serialization.
public Item MyItem
{
    get => null;   // Serializes to null; won't appear in the XML output.
    set
    {
        // When deserialize old version, this does what is needed.
        if (value != null)
            _myNewItem = MakeItemWrapperFromItem(value);
    }
}
// The new member.
public ItemWrapper MyNewItem
{
    get => _myNewItem;
    set => _myNewItem = value;
}
private ItemWrapper _myNewItem;

private ItemWrapper MakeItemWrapperFromItem(Item value)
{
    // Your code here.
}


方法2

子类

XMLSerializer

,并在那里控制序列化/反序列化。

如何:控制派生类的序列化

我喜欢这个版本的想法,但不幸的是“Item”并没有这样做。

但是有更高版本号吗?通常,版本控制仅在将成为 XML 文件“根”的类上完成。

这使得 XMLSerializer 的子类可以轻松处理不同的版本。

© www.soinside.com 2019 - 2024. All rights reserved.