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

C# XML反序列化:将编译期已知元素转为局部变量遇异常

解决XML反序列化时将已知未知元素转为局部变量的问题

问题背景

编译期明确知道XML中存在某些元素,但目标标记了[Serializable]的类没有对应成员,需要将这些元素反序列化为局部变量而非类成员。当前通过[XmlAnyElement]收集未知元素后,在AfterDeserialize方法中尝试将其反序列化为string类型时抛出XML异常,需要通用解决方案。

报错原因

原代码中DeserializeXmlElement<string>方法直接使用XmlSerializer反序列化XmlElement.OuterXml,但XmlSerializer默认序列化string类型时会生成<string>节点,而待反序列化的是<TheFooString>I'm from Foo.A</TheFooString>,根节点名称不匹配,导致反序列化失败。

解决方案

针对不同类型的元素,提供两种通用处理方式:

1. 字符串类型直接提取InnerText

对于字符串类型的元素,无需使用XmlSerializer,直接读取XmlElement.InnerText即可获取内容,这是最简便的方式。

2. 复杂类型指定XmlRootAttribute

如果是复杂类型的元素,需要创建XmlRootAttribute并指定其名称与目标XmlElement的名称一致,让XmlSerializer识别正确的根节点。

修改后的代码示例

修改Bar.A类中的DeserializeXmlElement方法,兼容字符串和复杂类型的反序列化:

namespace Bar
{
    [Serializable()]
    public class A
    {
        public string TheBarString { set; get; }

        [XmlAnyElement]
        public List<XmlElement> UnknownElements { get; set; }

        public static A Deserialize(string _sXml)
        {
            if (_sXml != string.Empty)
            {
                XmlSerializer serializer = new XmlSerializer(typeof(A));
                using (XmlReader xmlReader = XmlReader.Create(new StringReader(_sXml)))
                {
                    A instance = (A)serializer.Deserialize(xmlReader);
                    instance.AfterDeserialize();
                    return instance;
                }
            }
            return null;
        }

        static protected T DeserializeXmlElement<T>(XmlElement xmlElement)
        {
            // 针对字符串类型直接返回InnerText
            if (typeof(T) == typeof(string))
            {
                return (T)(object)xmlElement.InnerText;
            }

            // 针对复杂类型,指定XmlRoot与元素名称一致
            XmlRootAttribute xmlRoot = new XmlRootAttribute(xmlElement.Name);
            XmlSerializer serializer = new XmlSerializer(typeof(T), xmlRoot);
            using (StringReader stringReader = new StringReader(xmlElement.OuterXml))
            {
                return (T)serializer.Deserialize(stringReader);
            }
        }

        public void AfterDeserialize()
        {
            if (UnknownElements == null) return;
            
            foreach (XmlElement xmlElement in UnknownElements)
            {
                if (xmlElement.Name == "TheFooString")
                {
                    try
                    {
                        string BorrowString = DeserializeXmlElement<string>(xmlElement);
                        // 这里可以使用BorrowString这个局部变量做后续处理
                        Console.WriteLine($"获取到TheFooString的值:{BorrowString}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }
            }
        }
    }
}

验证效果

执行原测试代码后,将不再抛出异常,成功获取到TheFooString的值并输出:

Foo.A foo= new Foo.A();
foo.TheFooString = "I'm from Foo.A";
string xml_foo = foo.ToXmlString();

Bar.A bar = Bar.A.Deserialize(xml_foo);
// 输出:获取到TheFooString的值:I'm from Foo.A

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:57:46