1. 介绍
既然我们决定把“LEGO 小人拆开看构造”,那就先搞清楚在 .NET 里有哪些工具能干这事。换句话说——有哪些标准类帮你把对象序列化和反序列化成不同格式,以及每个工具背后是什么。
.NET 的序列化家族怎么组织的
到目前为止(2025),.NET 提供了几种主要的序列化方式,每种都有自己的一套类和工具。最常见和主要的有:
- JSON 序列化 — 主要且最现代的选项,绝大多数项目都用它。
- XML 序列化 — 有点老派,但仍然经常使用。
- 二进制序列化 — 只在特定场景下用,通常通过现代第三方方案实现。
很多示例和大部分 .NET 9 代码都用的是 JSON,这不是潮流,而是行业标准。但 .NET 也支持别的方式 — 以备不时之需。
.NET 序列化里的主要角色
| 格式 | 序列化类 | 简单性 | 性能 | 安全性 | 是否流行 |
|---|---|---|---|---|---|
| JSON | |
🔥🔥🔥 | 🔥🔥🔥 | 🔥🔥🔥 | 最流行 |
| XML | |
🔥🔥 | 🔥🔥 | 🔥🔥 | 仍在使用 |
| JSON | Newtonsoft.Json (Json.NET) | 🔥🔥🔥 | 🔥🔥 | 🔥🔥🔥 | 非常流行 |
每个工具简评
- System.Text.Json:.NET 的新标准 JSON 序列化,自 .NET Core 3.0 出现,成为 .NET 5+ 的默认。快速、轻量、安全,作为 .NET 9 的内置功能“开箱即用”。 文档
- XmlSerializer:用于 XML 序列化的老牌方案。用法简单,但有一些限制(比如需要 public 类和公共属性)。适合兼容性和严格的数据契约场景。 文档
- Newtonsoft.Json:在 System.Text.Json 出现之前长期是事实上的 JSON 标准。常用于复杂场景(动态、私有属性等)。 文档
BinaryFormatter 到哪儿去了?
如果你在网上看到有人建议用 BinaryFormatter —— 那大概率是很老的教程。不要使用 BinaryFormatter:它因为安全问题在 .NET 9 中被移除了。现代的二进制序列化通常用第三方解决方案,比如 Protobuf 或 MessagePack。
2. 简单示例
我们用熟悉的游戏世界里的 Player 类做示例,展示序列化和反序列化的实际操作。
准备要序列化的类
// Player.cs
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
public List<string> Inventory { get; set; }
public Position Position { get; set; }
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
}
a) 用 System.Text.Json 做 JSON 的序列化和反序列化
using System.Text.Json;
Player aragorn = new Player
{
Name = "Aragorn",
Health = 100,
IsAlive = true,
Inventory = new List<string> { "sword", "bow", "healing potion" },
Position = new Position { X = 10, Y = 25 }
};
// 将 Player 对象序列化成 JSON 字符串
string json = JsonSerializer.Serialize(aragorn);
// 打印 JSON 到控制台
Console.WriteLine(json);
// 将 JSON 字符串反序列化回 Player 对象
Player? aragornClone = JsonSerializer.Deserialize<Player>(json);
// 检查克隆是否有效 :)
Console.WriteLine(aragornClone?.Name); // 应该输出 "Aragorn"
就这么简单 —— 没有“巫术”或额外的属性。接下来看看 XML 是怎么做的。
b) 用 XmlSerializer 做 XML 的序列化和反序列化
using System.Xml.Serialization;
// 为 Player 类创建序列化器
XmlSerializer serializer = new XmlSerializer(typeof(Player));
// 序列化到文件
using FileStream fs = new FileStream("aragorn.xml", FileMode.Create);
serializer.Serialize(fs, aragorn); // 把 Aragorn 保存到 XML 文件
// 从文件反序列化
using FileStream fs = new FileStream("aragorn.xml", FileMode.Open);
Player aragornFromXml = (Player) serializer.Deserialize(fs)!;
Console.WriteLine(aragornFromXml.Name); // 应该输出 "Aragorn"
注意!XmlSerializer 要求类和属性是 public 的,并且要有无参数的默认构造函数(如果你重写了构造函数,确保有一个无参的 public 构造函数)。否则序列化会失败。
c) 用 Newtonsoft.Json 做 JSON 的序列化和反序列化
using Newtonsoft.Json; // 别忘了通过 NuGet 添加 Newtonsoft.Json 包!
// 序列化
string json2 = JsonConvert.SerializeObject(aragorn);
// 反序列化
Player? aragornFromNewtonsoft = JsonConvert.DeserializeObject<Player>(json2);
Console.WriteLine(aragornFromNewtonsoft?.Name); // 还是 "Aragorn"
看起来几乎一样,但 Newtonsoft.Json 提供了很多额外选项 —— 比如可以序列化私有字段、配置格式化和处理复杂场景。
4. 有用的细节
标准序列化器和它们的能力
| 类 | 格式 | 是否内置于 .NET | 需要 NuGet 包? | 适合文件 | 适合 API | 简单性 |
|---|---|---|---|---|---|---|
|
JSON | 是 | 否 | 是 | 是 | 轻量 |
|
JSON | 否 | 是 | 是 | 是 | 轻量 |
|
XML | 是 | 否 | 是 | 常用 | 轻量 |
怎么选择哪个类?
如果你不知道为啥需要 XML —— 几乎总是选 JSON 和 System.Text.Json。它更快、更简单,符合现代做法。
选择 XML 的场景:
- 你要和需要 XML 的老系统集成。
- 你需要严格的 schema 和数据结构校验。
- 结构很大、很稳定,并且正式兼容性很重要(配置、设置、与企业系统交换数据)。
选择 JSON 的场景:
- 你在做现代应用,与 web 或移动端交互。
- 你需要简单、可读且紧凑的格式。
- 你不想引入额外依赖。
选择 Newtonsoft.Json 的场景:
- 你需要序列化私有字段、做复杂定制、完全的灵活性。
- 或者项目已经用它了,当前不适合迁移。
5. 常见错误和陷阱
编码问题。 主要的序列化类(尤其是文件操作时)使用 UTF-8。如果看到乱码,检查读写文件时的编码设置。关于编码的文档。
不支持的类型。 有些标准序列化器(尤其是 XML)不能序列化像字典(Dictionary)、私有/受保护字段、事件、委托和接口这类类型。通常只支持公共的简单属性和类。
类版本变化。 当你改变类结构(添加/重命名/移除属性)时,旧的数据可能无法读取或反序列化出错。要考虑格式版本管理。
Null 值。 反序列化时,如果数据里没有某字段,对应属性会被赋默认值(引用类型为 null)。别忘了做空值检查。
属性特性(Attributes)。 为了精细控制,常用像 [JsonIgnore]、[XmlElement] 之类的特性。它们可以用来排除属性、修改元素名和调整格式 —— 这些内容会在后面的讲座里详细讲。
GO TO FULL VERSION