C#如何将XML反序列化为dynamic对象

1次阅读

C#不支持xml直接反序列化为dynamic,但可通过XDocument递归构建ExpandoObject实现;也可用DynamicXml等第三方库简化操作,适用于配置读取等场景。

C#如何将XML反序列化为dynamic对象

C#本身不支持直接将XML反序列化为dynamic对象(如ExpandoObject),因为XmlSerializer要求编译时已知类型,而dynamic是运行时绑定的。但可以通过组合XDocument解析 + 递归构建ExpandoObject来实现等效效果。

使用XDocument手动构建ExpandoObject

这是最常用、可控性最强的方式:先用XDocument.Load()XDocument.Parse()加载XML,再递归遍历节点,把元素和属性转为ExpandoObject的属性。

  • 元素名作为属性名,文本内容作为值(若无子元素)
  • 同名多个子元素转为List
  • 属性(XAttribute)可存入特殊字典字段(如@attrName)或单独对象
  • 需注意类型推断——XML文本默认是字符串,如需数字/布尔,需自行尝试转换(int.TryParse等)

封装一个通用的XmlToDynamic方法

以下是一个简洁可用的辅助方法(支持嵌套、数组、属性):

public static dynamic XmlToDynamic(string xml) {     var doc = XDocument.Parse(xml);     return ToExpando(doc.Root); }  private static dynamic ToExpando(XElement element) {     var expando = new ExpandoObject() as IDictionary;          // 添加属性(前缀@)     foreach (var attr in element.Attributes())         expando[$"@{attr.Name}"] = attr.Value;      // 处理子元素     var elements = element.Elements().ToArray();     var grouped = elements.GroupBy(e => e.Name).ToList();      foreach (var g in grouped)     {         var value = g.Count() == 1              ? ToExpandoOrValue(g.First())              : g.Select(ToExpandoOrValue).Cast().ToList();         expando[g.Key.ToString()] = value;     }      // 如果没有子元素,返回文本值(并尝试转基础类型)     if (!elements.Any())     {         var text = element.Value.Trim();         if (int.TryParse(text, out int i)) return i;         if (bool.TryParse(text, out bool b)) return b;         if (double.TryParse(text, out double d)) return d;         return text;     }      return expando; }  private static object ToExpandoOrValue(XElement el) =>     !el.Elements().Any() && !el.Attributes().Any()          ? el.Value.Trim()          : ToExpando(el);

使用第三方库(如DynamicXml)

社区有轻量封装库简化该流程,例如DynamicXml

  • NuGet安装:Install-Package DynamicXml
  • 用法简单:dynamic xml = new DynamicXml(xmlString);
  • 支持点语法访问:xml.Book.Titlexml.Book.Author[0].Name
  • 内部仍基于XDocument,但屏蔽了构建细节,适合快速原型

注意事项与限制

这类方案不是真正的“反序列化”,而是运行时结构映射,需注意:

  • 无法享受XmlSerializer命名空间、CDATA、注释等高级特性支持
  • 性能不如强类型反序列化(尤其大数据量),但对配置类小XML足够快
  • dynamic丢失编译期检查,建议仅用于脚本化、配置读取或临时数据处理场景
  • 若需双向(dynamic → XML),需额外实现ToXml()逻辑

Copyright ©  SEO

 Theme by Puock