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
相关产品推荐
相关产品推荐

