XmlSerializer 序列化 POCO 类需满足:类有 public 无参构造函数;字段/属性为 public 且可读写;泛型集合须用 List<T> 等具体类型而非接口;通过 [XmlIgnore]、[XmlElement] 等特性控制序列化行为;首次使用有性能开销,建议缓存实例。

XmlSerializer 能直接序列化大多数 POCO 类,但必须满足几个硬性条件,否则运行时抛出 InvalidOperationException 或静默失败。
类必须有无参构造函数才能被 XmlSerializer 处理
XmlSerializer 在反序列化时需要通过反射调用默认构造函数创建实例。如果类只定义了带参数的构造函数,Deserialize 会直接失败,错误信息类似:There was an error reflecting type 'MyClass'。
实操建议:
- 显式声明一个
public MyClass() { },哪怕内容为空 - 若使用记录(record)或 C# 12 主构造函数语法,需额外补一个无参构造函数,例如:
public Person() : this("", 0) { } - 抽象基类、接口、
sealed类本身不构成问题,但它们的子类仍需各自提供无参构造函数
字段和属性必须是 public 才会被默认序列化
XmlSerializer 只处理 public 字段和 public 属性(含 get/set),private、protected、internal 成员均被忽略,且不会报错。
常见错误现象:
- 序列化后 XML 中缺少预期节点,检查对应字段/属性是否为
private string _name;—— 改成public string Name { get; set; }即可 - 只读属性(如
public string FullName => $"{FirstName} {LastName}";)不会被序列化,除非手动用[XmlElement]标记并配合set(但语义上不合理,建议改用计算字段+额外存储字段) -
public List<Item> Items { get; } = new();这种只读集合属性无法反序列化(因无set),应改为public List<Item> Items { get; set; } = new();
数组、List 和嵌套对象能直接序列化,但要注意类型声明方式
XmlSerializer 对泛型集合支持有限:它原生支持 ArrayList、T[]、List<T>(.NET Framework 2.0+),但不支持 IList<T>、ICollection<T> 等接口类型作为属性类型。
使用场景与参数差异:
- 用
public Item[] Items { get; set; }最稳妥,生成 XML 是重复的<Items>...</Items>元素 - 用
public List<Item> Items { get; set; }也可行,但需确保Item类本身可被序列化(含无参构造函数等) - 若属性类型是
public IList<Item> Items { get; set; },运行时会抛出InvalidOperationException:“Cannot serialize interface”——必须改成具体实现类型 - 嵌套对象无需额外配置,只要其类型满足前述条件(public 属性 + 无参构造函数),
XmlSerializer会自动递归处理
忽略字段、重命名元素、控制空值行为要用特性标注
默认行为往往不够用:比如想跳过某个敏感字段、把 CustomerName 输出为 <name>、让 null 值不生成对应 XML 元素。这些都得靠特性。
关键特性与典型用法:
- 跳过字段:
[XmlIgnore]加在属性上,如[XmlIgnore] public string ApiKey { get; set; } - 重命名元素:
[XmlElement("name")]让属性输出为<name>xxx</name>;[XmlAttribute("id")]输出为<item id="123"> - 控制 null 行为:
[XmlElement(IsNullable = true)]会让 null 值输出为<field xsi:nil="true"/>;设为false(默认)则完全不输出该元素 - 指定根节点名:
[XmlRoot("customer-list")]作用于类,影响整个 XML 的最外层标签
注意:[NonSerialized] 对 XmlSerializer 无效,它只对 BinaryFormatter 起作用;同样,[DataContract] 系列特性也不被 XmlSerializer 识别。
最容易被忽略的是:即使所有代码写对了,第一次调用 new XmlSerializer(typeof(MyClass)) 时,.NET 会动态生成临时序列化程序集,这个过程有明显延迟。高频调用场景下建议缓存 XmlSerializer 实例,或用 Sgen.exe 预生成序列化程序集。否则你会在性能分析中看到意外的 JIT 和反射开销。


















