序列化** 是將物件狀態(欄位、屬性)轉換為可儲存、可傳輸的位元組流或文本格式;**反序列化** 是逆向過程。兩者結合實現物件的持久化、跨進程/跨機器傳遞、快照備份等場景。
[Serializable] 屬性(JSON 除外)。XmlSerializer)特點:人類可讀、跨平台、僅序列化 `public` 讀寫屬性/欄位,**不支援私有欄位**、**不支援介面/繼承多型**、**不支援字典**。
[Serializable]
public class User {
public int Id { get; set; }
public string Name { get; set; }
private string _secret; // 不會被序列化
}
// 序列化
var user = new User { Id = 1, Name = "張三" };
var xs = new XmlSerializer(typeof(User));
using (var sw = new StreamWriter("user.xml"))
xs.Serialize(sw, user);
// 反序列化
User u2;
using (var sr = new StreamReader("user.xml"))
u2 = (User)xs.Deserialize(sr);
// 輸出 XML
//
// 1 張三
BinaryFormatter) — 已過時/不安全⚠️ 警告:.NET 5+ 標記為 `Obsolete`,**存在遠程代碼執行漏洞**,**嚴禁用於非信任數據**。僅維護舊專案時了解。
[Serializable]
public class User { public int Id; public string Name; private string _pwd; } // 私有也會序列化
var bf = new BinaryFormatter();
using (var fs = new FileStream("user.bin", FileMode.Create))
bf.Serialize(fs, user);
User u2;
using (var fs = new FileStream("user.bin", FileMode.Open))
u2 = (User)bf.Deserialize(fs); // 私有欄位 _pwd 完整還原
using System.Text.Json;
var json = JsonSerializer.Serialize(user, new JsonSerializerOptions { WriteIndented = true });
// {"Id":1,"Name":"張三"}
var u2 = JsonSerializer.Deserialize(json);
// 支援不可變類型、record、介面多型(需配置)
using Newtonsoft.Json;
var settings = new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.Auto, // 支援多型反序列化
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented
};
var json = JsonConvert.SerializeObject(user, settings);
var u2 = JsonConvert.DeserializeObject(json, settings);
| 維度 | JSON | XML |
|---|---|---|
| 體積 | 小 (~30-50%) | 大(標籤開銷) |
| 解析速度 | 快 | 慢 |
| 可讀性 | 高 | 中 |
| 私有欄位 | 可選(需配置) | 不支援 |
| 多型支援 | 強($type / TypeNameHandling) | 弱 |
| 流式處理 | 支援 (Utf8JsonReader) | 支援 (XmlReader) |
支援私有欄位、版本容忍、介面多型,需標記 `[DataContract]`、`[DataMember]`。
[DataContract]
public class User {
[DataMember] public int Id { get; set; }
[DataMember] public string Name { get; set; }
[DataMember] private string _pwd; // 私有也可序列化
}
痛點:控件繼承 `Control` → `Component` → `MarshalByRefObject`,**無法直接序列化**(綁定視窗句柄、非托管資源、線程親和性)。
// 1. 定義可序列化的純數據類 (DTO)
[Serializable]
public class MyControlState {
public string Text { get; set; }
public Color BackColor { get; set; }
public int[] SelectedIndices { get; set; }
// 僅包含需持久化的「狀態」,無事件、無方法、無視窗句柄
}
// 2. 控件提供狀態同步方法
public class MyCustomControl : Control {
public MyControlState GetState() => new MyControlState {
Text = this.Text,
BackColor = this.BackColor,
SelectedIndices = this.ListBox.SelectedIndices.Cast().ToArray()
};
public void ApplyState(MyControlState state) {
this.Text = state.Text;
this.BackColor = state.BackColor;
this.ListBox.SelectedIndices.Clear();
foreach (var i in state.SelectedIndices) this.ListBox.SelectedIndices.Add(i);
}
}
// 3. 序列化時:control.GetState() → 序列化 DTO
// 4. 反序列化時:DTO → new Control() → control.ApplyState(dto)
優勢:完全脫離 UI 框架、可跨平台、版本兼容性強、單元測試友好。
需要跨語言/跨平台/安全/高效能?
├─ 是 → System.Text.Json / Newtonsoft.Json / protobuf-net / MessagePack
└─ 否 → 僅 .NET 內部、需私有欄位/多型/版本容忍?
├─ 是 → DataContractSerializer / BinaryFormatter(舊專案維護)
└─ 否 → 僅配置文件/人工編輯?
├─ 是 → XmlSerializer
└─ 否 → JSON (預設首選)