CodeGym /课程 /C# SELF /用 XmlSerializer 将对象序列化成 XML

用 XmlSerializer 将对象序列化成 XML

C# SELF
第 44 级, 课程 2
可用

1. 介绍

XML 是 eXtensible Markup Language 的缩写。想象一个既严格又健谈的 JSON,不停地重复“我有结构,相信我!”。XML 是一种文本格式,数据被标签包裹着:

<Player>
  <Name>Aragorn</Name>
  <Health>100</Health>
</Player>

为什么现在还要把对象序列化成 XML?

  • XML 仍然在大型(经常是“遗留”)系统之间的集成中广泛使用,特别是需要严格按模式(XSD)校验的场景。
  • 在企业配置中常常用到 XML(例如在老版本 .NET 中的 App.config 和 Web.config)。
  • 当你需要数据结构“自描述”时,XML 很合适。

有趣的事实: XML 的设计初衷就是要尽可能“可扩展”和可验证;这也就是它名字的来源。可以对它按模式做校验——这是 JSON 默认不具备的。

XmlSerializer:主角

在 .NET 里负责对象到 XML 序列化的是类 System.Xml.Serialization.XmlSerializer。

  • 它把对象的 public 属性和字段变成 XML 元素,反过来也能根据 XML 恢复对象。
  • 只对公开的类型和成员有效。
  • 不会序列化 private 字段和属性 —— 只有公开的成员会被处理!
  • 被序列化的类需要有一个无参的构造函数。

注意: 如果你的类不满足这些要求,XmlSerializer 将无法工作——在序列化或反序列化时会抛出异常。

2. 简单示例 — 把对象序列化成 XML

我们来看看怎么把我们常用的类 Player 序列化成 XML。

步骤 1. 描述类

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }
    public bool IsAlive { get; set; }

    // 重要:需要一个 public 的无参构造函数!
    public Player() { }

    // 可选:为了方便
    public Player(string name, int health, bool isAlive)
    {
        Name = name;
        Health = health;
        IsAlive = isAlive;
    }
}

步骤 2. 序列化到文件

using System.Xml.Serialization;

Player aragorn = new Player("Aragorn", 100, true);

// 1. 创建针对 Player 类型的序列化器
XmlSerializer serializer = new XmlSerializer(typeof(Player));

// 2. 打开文件写入(不存在时会创建)
using FileStream fs = new FileStream("player.xml", FileMode.Create);

// 3. 把对象序列化为 XML
serializer.Serialize(fs, aragorn);

结果 (player.xml):

<?xml version="1.0"?>
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Aragorn</Name>
  <Health>100</Health>
  <IsAlive>true</IsAlive>
</Player>

最简单流程的可视化示意


内存中的对象  --->  XmlSerializer.Serialize()  --->  磁盘上的 XML 文件

3. 反序列化 — 从 XML “复活” 对象

当你需要读取之前序列化的对象时,过程正好相反:

using FileStream fs = new FileStream("player.xml", FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
Player player = (Player)serializer.Deserialize(fs);

Console.WriteLine($"姓名: {player.Name}, 生命值: {player.Health}, 存活: {player.IsAlive}");

程序会输出: 姓名: Aragorn, 生命值: 100, 存活: True

4. 序列化到字符串 — 不仅仅是文件

序列化到字符串

不一定非要写到文件。有时候你需要把 XML 作为字符串发到网络上,或显示在界面上。

using System.IO;
using System.Xml.Serialization;

Player player = new Player("Frodo", 42, true);

XmlSerializer serializer = new XmlSerializer(typeof(Player));
StringWriter stringWriter = new StringWriter();
serializer.Serialize(stringWriter, player);

string xmlString = stringWriter.ToString();
Console.WriteLine(xmlString); // 整个 XML 字符串会显示在屏幕上!

从字符串反序列化

同样可以从字符串而不是文件反序列化对象:

string xml = "<Player Name=\"Frodo\"><HP>42</HP></Player>";
XmlSerializer serializer = new XmlSerializer(typeof(Player));

using StringReader stringReader = new StringReader(xml);
Player frodo = (Player)serializer.Deserialize(stringReader);
Console.WriteLine(frodo.Name); // Frodo

5. 自定义 XML:用属性控制结构

有时候默认行为不够好。生成的 XML 太啰嗦,或者标签名和目标不一致。这时可以用各种“魔法”属性直接告诉序列化器如何表示类的成员。

最常用的:

  • [XmlElement]
    — 指定元素名。
  • [XmlAttribute]
    — 把字段作为 XML 属性,而不是元素。
  • [XmlIgnore]
    — 从序列化中排除该属性。
  • [XmlArray]
    和
    [XmlArrayItem]
    — 控制集合的包装和内部元素名。

使用示例:

public class Player
{
    [XmlAttribute]
    public string Name { get; set; }
    [XmlElement("HP")]
    public int Health { get; set; }
    [XmlIgnore]
    public bool IsTempSessionPlayer { get; set; }
}

生成的 XML:

<Player Name="Aragorn">
  <HP>100</HP>
</Player>

常用序列化属性表

属性 影响 示例用法
[XmlAttribute]
把属性变成 XML 属性
<Player Name="Aragorn">...</Player>
[XmlElement]
改变标签名
<HP>100</HP>
而不是
<Health>100</Health>
[XmlIgnore]
完全从序列化中排除该属性 —
[XmlArray]
改变集合外层包装的名字
<Heroes> ... </Heroes>
[XmlArrayItem]
改变集合中元素的名字
<Hero>...</Hero>

复杂集合序列化示例:

public class GameWorld
{
    [XmlArray("Heroes")]
    [XmlArrayItem("Hero")]
    public List<Player> Players { get; set; } = new List<Player>();
}

XML:

<GameWorld>
  <Heroes>
    <Hero Name="Legolas">
      <HP>90</HP>
    </Hero>
    <!-- ... -->
  </Heroes>
</GameWorld>

更多关于自定义 XML 的内容我们会在后面的课里讲! :P

2
任务
C# SELF, 第 44 级, 课程 2
已锁定
序列化和反序列化对象列表
序列化和反序列化对象列表
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION