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 且沒有參數的構造函式)。否則序列化會失敗。
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)、私有/受保護欄位、事件、delegate 和介面這類類型。通常只支援公開的簡單屬性與類別。
類別版本差異。 如果你更改了類別結構(新增/重新命名/刪除屬性),舊的已儲存資料可能無法正確讀取或反序列化。要規劃格式的版本管理。
Null 值。 反序列化時,如果資料中缺少某個欄位,對應的屬性會取得預設值(對於參考型別是 null)。記得做好檢查。
屬性標註(attributes)。 要做精細控制常用像 [JsonIgnore]、[XmlElement] 這類屬性。它們可以排除屬性、改變元素名稱或控制格式——詳細內容會在後續講座討論。
GO TO FULL VERSION