.NET中XmlSerializer的使用和自定义映射

2次阅读

xmlSerializer默认只序列化public实例字段或属性;private字段、Static成员、只读属性等均被跳过,需确保属性有public get和set访问器或使用[XmlElement]等特性控制。

.NET中XmlSerializer的使用和自定义映射

XmlSerializer序列化时字段不输出,为什么?

默认情况下,XmlSerializer 只序列化 public 实例字段或属性。private 字段、static 成员、只读属性(get-only)、自动实现属性但没有 set 访问器,都会被跳过。

常见错误现象:

public class Person { private string _name = "Alice"; public string Name => _name; }

——序列化后 XML 中没有 Name 节点。

  • 确保属性有 public get set(哪怕空实现):public String Name { get; set; }
  • 若必须用只读逻辑,可加 [XmlElement] 并配合 ShouldSerializeXXX() 模式(见下节)
  • 字段需为 public 才参与序列化;否则改用属性 + 特性标注

如何控制元素名、忽略字段、调整顺序?

靠特性(Attribute)精细控制映射,不是靠命名约定或配置文件。

常用特性及作用:

  • [XmlElement("alias")]:指定 XML 元素名,如把 FirstName 映射为
  • [XmlAttribute("id")]:将属性序列化为同级元素的 attribute,而非子元素
  • [XmlIgnore]:彻底跳过该成员(比设为 private 更明确、更易维护)
  • [XmlElement(Order = 2)]:控制子元素在 XML 中的出现顺序(默认按声明顺序,但显式设 Order 更可靠)

示例:

[XmlRoot("person")] public class Person {     [XmlElement("full-name")]     public string FullName { get; set; }      [XmlAttribute("version")]     public int Version { get; set; }      [XmlIgnore]     public bool IsDirty { get; set; } }

ShouldSerializeXXX() 方法是怎么起作用的?

这是 XmlSerializer 的隐式约定机制:如果存在签名形如 bool ShouldSerialize() 的 public 实例方法,它会在序列化前被调用;返回 false 则跳过该属性。

这比 [XmlIgnore] 灵活,因为判断逻辑可依赖其他字段状态。

  • 方法名必须严格匹配:如属性叫 BirthDate,方法就得叫 ShouldSerializeBirthDate()
  • 返回类型必须是 bool,无参数,且为 public
  • 不能带泛型、不能是 static、不能重载
  • 它不参与反序列化,仅影响序列化行为

典型场景:只在 HasPhoto == true 时才输出 PhotoData

public byte[] PhotoData { get; set; } public bool HasPhoto { get; set; }  public bool ShouldSerializePhotoData() => HasPhoto;

反序列化失败的常见原因和绕过方式

最常见的报错是 InvalidOperationException,提示“未找到无参构造函数”或“无法将字符串转换为 XXX 类型”。这是因为 XmlSerializer 在反序列化时必须调用目标类型的 public 无参构造函数,且所有要赋值的属性/字段必须支持从字符串解析(或有 TypeConverter)。

  • 类必须有 public 无参构造函数(即使你写了带参构造,也得额外补一个空的)
  • 枚举字段若含未知值,会失败;可用 [XmlEnum("unknown")] 标注默认值,或提前预处理 XML
  • 日期格式必须符合 XSD 标准(如 2023-10-05T14:30:00),否则需自定义 TypeConverter 或改用 DateTimeOffset
  • 集合类型推荐用 List 或数组;IEnumerable 或自定义集合类需额外处理(如加 [XmlArray] + [XmlArrayItem]

绕过强类型约束的一个办法是先反序列化为 XElement,再手动提取——但这意味着放弃 XmlSerializer 的便利性,转而用 linq to XML。

text=ZqhQzanResources