CodeGym /课程 /C# SELF /序列化的基本示例

序列化的基本示例

C# SELF
第 45 级, 课程 0
可用

1. 介绍

提醒:序列化是把对象的状态保存成字符串、文件或流的一种方式,以便以后可以恢复该对象(反序列化)——这样你就可以重新得到具有相同数据的对象。

典型场景:
1) 你有一个对象,例如一个包含名字和年龄的用户。
2) 需要保存它——通过网络传输、写入文件,或者比如转换成 JSON 格式。
3) 然后从字符串/文件里把数据拿回来——你又得到一个对象!

在 C# 中这只需几行代码。我们来看看具体怎么做。

我们的应用

我们在开发一个小应用“联系人管理器”。假设我们有一个要序列化的类 Person。

public class Person
{
    // 公共属性对序列化是必须的!
    public string Name { get; set; }
    public int Age { get; set; }

    // 无参数构造函数对 XmlSerializer 是必须的
    public Person() { }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

如果你不熟悉这种语法别担心——在课程后面会详细讲解类和属性。现在把它当作实验用的数据模型。注意:公共属性 Name 和 Age 对序列化很重要,而 XmlSerializer 需要一个公共的无参构造函数。

2. 使用 System.Text.Json 序列化为 JSON

最简单的例子

说了就给你看!下面是序列化为 JSON 的样子:

using System;
using System.Text.Json;

Person person = new Person("阿丽萨", 28);

// 序列化:把对象变成 JSON 字符串
string json = JsonSerializer.Serialize(person);

Console.WriteLine("JSON:");
Console.WriteLine(json);

屏幕上会显示什么?

JSON:
{"Name":"阿丽萨","Age":28}

很简单:对象 → JSON。就是这么神奇!

反序列化 —— 把东西还原回来

现在做反向操作——从 JSON 字符串恢复对象:

string json = "{\"Name\":\"鲍勃\",\"Age\":35}";

// 反序列化:从 JSON 字符串恢复出 Person 类型的对象
Person restored = JsonSerializer.Deserialize<Person>(json);

Console.WriteLine("恢复的对象:");
Console.WriteLine($"名字: {restored.Name}, 年龄: {restored.Age}");

结果:

恢复的对象:
名字: 鲍勃, 年龄: 35

注意:如果数据结构不匹配(例如没有某个属性),对应字段会保留默认值(引用类型为 null,数值类型为 0 等)。

3. 使用 XmlSerializer 进行 XML 的序列化/反序列化

第一次看 XML 序列化

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

Person person = new Person("卡佳", 22);

// 为 Person 类型创建序列化器
var serializer = new XmlSerializer(typeof(Person));

// 把 XML 写入文件
using (var stream = new FileStream("person.xml", FileMode.Create))
{
    serializer.Serialize(stream, person);
    // using 块结束时流会自动关闭
}
Console.WriteLine("XML 文件已创建!");

在文件 person.xml 中会出现类似这样的内容:

<?xml version="1.0"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>卡佳</Name>
  <Age>22</Age>
</Person>

重要点:
写入文件时使用的是流(Stream,例如 FileStream)。如果你想把序列化结果放到字符串里(比如要通过网络发送),可以用 StringWriter:

var serializer = new XmlSerializer(typeof(Person));
using (var sw = new StringWriter())
{
    serializer.Serialize(sw, person);
    string xmlString = sw.ToString();
    Console.WriteLine(xmlString);
}

从 XML 反序列化

using (var stream = new FileStream("person.xml", FileMode.Open))
{
    // 别忘了转换到需要的类型!
    Person restored = (Person)serializer.Deserialize(stream);
    Console.WriteLine($"名字: {restored.Name}, 年龄: {restored.Age}");
}

再提醒一次:XmlSerializer 要求被序列化的类必须有公共的默认(无参)构造函数。

4. 文件与字符串的处理:选哪个?

在真实场景中,序列化可能直接输出为字符串(用于网络传输/数据库存储)或写入文件(用于长期保存)。

序列化为字符串(例如,用于通过 API 传输):

  • JSON:用 JsonSerializer.Serialize(obj)。
  • XML:用 StringWriter。

序列化到文件(例如导出/备份):

  • JSON:把字符串用常规文件写入方法保存到文件。
  • XML:直接用 XmlSerializer 写到流里。

示例:序列化到文件并恢复(JSON)

using System.IO;
using System.Text.Json;

Person person = new Person("汤姆", 42);

// 序列化为字符串
string json = JsonSerializer.Serialize(person);

// 写入文件
File.WriteAllText("contact.json", json);

// 从文件读取
string readJson = File.ReadAllText("contact.json");
Person restored = JsonSerializer.Deserialize<Person>(readJson);

Console.WriteLine($"{restored.Name}, 年龄: {restored.Age}");

5. JSON 与 XML 的比较

过程可视化

为了不搞混,这里是序列化/反序列化过程的示意:

flowchart LR
    A[对象] -- 序列化 --> B[字符串/文件/流]
    B -- 反序列化 --> C[对象]

    A -. JSON 或 XML .-> B
    B -. JSON 或 XML .-> C

可以把序列化想象成“收拾行李”,反序列化就是“到家后把行李 unpack(拆包)”。

比较表

功能 JSON (System.Text.Json) XML (XmlSerializer)
读/写字符串 ++ +
读/写文件 ++ ++
需要无参构造函数 否 是
对人类可读性 ++ +
严格的数据模式(校验) - ++
定制属性的灵活性 + ++
性能 ++ +
与互联网兼容性 ++ +

++ — 非常好,+ — 正常,- — 不支持

6. 如何在我们的应用里添加序列化

假设在“联系人管理器”里增加了把用户联系人列表保存到文件并恢复的功能。

上下文:我们有一个联系人列表(List<Person>)。

List<Person> contacts = new List<Person>
{
    new Person("瓦西娅", 30),
    new Person("彼佳", 25),
    new Person("玛莎", 27)
};

// 保存所有联系人 —— 序列化为 JSON
string jsonContacts = JsonSerializer.Serialize(contacts);
File.WriteAllText("contacts.json", jsonContacts);

// 恢复联系人列表
string readContactsJson = File.ReadAllText("contacts.json");
List<Person> restored = JsonSerializer.Deserialize<List<Person>>(readContactsJson);

foreach (var c in restored)
{
    Console.WriteLine($"{c.Name}, 年龄: {c.Age}");
}

同样的事情也可以用 XML 做,但有些细节不太一样。使用 XmlSerializer 序列化集合时通常会把列表包在一个单独的容器类(根元素)里——这样更容易控制格式和元素名称。

7. 序列化和反序列化的常见错误

错误 #1:序列化和反序列化时类型不匹配。
你序列化的是 List<Person> —— 那么反序列化也必须是 List<Person>,而不是 List<object> 或 IEnumerable<Person>。否则会报错或得到意外结果。

错误 #2:尝试序列化非公共字段或属性。
常见序列化器(JsonSerializer, XmlSerializer)处理公共成员。如果属性没有公共的 getter/setter,值可能不会进入 JSON/XML,然后你会疑惑为什么是 null。

错误 #3:缺少无参构造函数。
对 XmlSerializer 来说,公共的默认构造函数是必须的。没有的话反序列化会抛异常。

错误 #4:错误理解对象引用。
如果一个对象引用另一个对象,序列化是“按值”进行的(作为嵌套对象)。引用本身不会被保存,这可能导致数据重复或循环引用问题。

错误 #5:尝试混用序列化格式。
XML 和 JSON 是不同的格式和序列化器。不能把 JSON 字符串交给 XmlSerializer,反之亦然——会报错。

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