You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现XmlSerializer序列化用新类名、反序列化兼容新旧类名?

场景与问题

我原本有如下类定义:

public class Foo
{

}

它可反序列化为以下XML,这类文件已存在于客户端机器中:

<?xml version="1.0"?>
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

</Foo>

现在要将该类重命名为Footastic:

public class Footastic
{

}

新序列化操作需生成根节点为Footastic的XML:

<?xml version="1.0"?>
<Footastic xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

</Footastic>

核心需求:反序列化时同时兼容旧根节点Foo和新根节点Footastic,但新序列化只能输出Footastic作为根节点。直接给Footastic添加[XmlRoot("Foo")]特性会导致新序列化也输出Foo,不符合要求。

现有序列化/反序列化代码如下:

现有反序列化代码

public static T? Deserialize<T>(string fileName)
{
    if (!File.Exists(fileName))
        return default;

    using FileStream streamReader = new(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using var xr = XmlReader.Create(streamReader);
    XmlSerializer xmlDeSerializer = new(typeof(T));
    return (T?)xmlDeSerializer.Deserialize(xr);
}

现有序列化代码

public static void Serialize<T>(T? value, string fileName)
{
    if (value is null)
        return;

    Directory.CreateDirectory(Path.GetDirectoryName(fileName) ?? "");

    using FileStream fileStream = new(fileName, FileMode.Create, FileAccess.Write, FileShare.Write);
    using var streamWriter = XmlWriter.Create(fileStream, new()
    {
        Encoding = Encoding.UTF8,
        Indent = true
    });

    XmlSerializer xmlSerializer = new(typeof(T));
    xmlSerializer.Serialize(streamWriter, value);
}
解决方案

方法一:修改XML根节点后反序列化

读取XML内容,将旧根节点Foo精准替换为Footastic后再进行反序列化,适合结构简单的XML场景:

public static T? Deserialize<T>(string fileName)
{
    if (!File.Exists(fileName))
        return default;

    // 使用XDocument精准修改根节点名称
    var doc = XDocument.Load(fileName);
    if (doc.Root != null && doc.Root.Name.LocalName == "Foo")
    {
        doc.Root.Name = "Footastic";
    }

    using var stringReader = new StringReader(doc.ToString());
    using var xr = XmlReader.Create(stringReader);
    XmlSerializer xmlDeSerializer = new(typeof(T));
    return (T?)xmlDeSerializer.Deserialize(xr);
}

方法二:动态创建兼容的XmlSerializer实例

先检测XML的根节点名称,根据名称创建对应配置的XmlSerializer:如果根节点是Foo,就创建指定根节点为Foo的序列化器;否则使用默认序列化器。这种方法无需修改XML内容,适合复杂XML场景:

public static T? Deserialize<T>(string fileName)
{
    if (!File.Exists(fileName))
        return default;

    XmlSerializer serializer;
    // 先读取根节点名称
    using (var xr = XmlReader.Create(fileName))
    {
        xr.MoveToContent();
        var rootName = xr.LocalName;
        serializer = rootName == "Foo" 
            ? new XmlSerializer(typeof(T), new XmlRootAttribute("Foo")) 
            : new XmlSerializer(typeof(T));
    }

    using FileStream streamReader = new(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
    using var xr = XmlReader.Create(streamReader);
    return (T?)serializer.Deserialize(xr);
}

序列化代码无需改动

原序列化代码保持不变即可,默认情况下XmlSerializer会使用类名Footastic作为根节点,生成符合要求的XML。

内容的提问来源于stack exchange,提问作者Rand Random

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 01:55:27