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;
    }
}

如果你還不熟悉這種語法別擔心——課程後面會詳細講解類別和屬性。現在先把它當作實驗用的資料模型。注意:公開屬性 NameAge 對序列化很重要,而 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 要求被序列化的類別有公開的無參數建構子(constructor)。

4. 跟檔案與字串打交道:要選哪個?

在真實場景中,序列化可能直接成為字串(用於網路傳輸/存 DB)或成為檔案(用於長期儲存)。

序列化成字串(例如用於 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 vs XML 的比較

流程視覺化

為了不搞混,這是序列化與反序列化的流程圖:

flowchart LR
    A[物件] -- 序列化 --> B[字串/檔案/串流]
    B -- 反序列化 --> C[物件]

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

可以把序列化想像成「把行李打包」,反序列化就是「回到家把行李打開」。

比較表

功能 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:嘗試序列化非公開欄位或屬性。
常見序列化器(JsonSerializerXmlSerializer)只會處理公開的成員。如果屬性沒有公開的 getter/setter,值可能不會進到 JSON/XML,你就會納悶為什麼是 null

錯誤 #3:缺少無參數建構子。
對於 XmlSerializer,公開的無參數建構子是必需的。若沒有,反序列化會拋出例外。

錯誤 #4:對物件參考的誤解。
如果一個物件持有對另一個物件的引用,序列化會以「值」的方式序列化(如巢狀物件)。引用本身不會被保留,可能導致資料重複或在有循環引用時出問題。

錯誤 #5:混用序列化格式。
XMLJSON 是不同的格式、不同的序列化器。不能把 JSON 字串傳給 XmlSerializer 或反過來——會出錯。

2
任務
C# SELF, 等級 45, 課堂 0
上鎖
物件的 JSON 序列化與反序列化
物件的 JSON 序列化與反序列化
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION