首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 實體類序列化完全指南:XML、二進制、JSON 與自定義控件序列化策略

     編輯:關於C語言

什麼是序列化?

序列化** 是將物件狀態(欄位、屬性)轉換為可儲存、可傳輸的位元組流或文本格式;**反序列化** 是逆向過程。兩者結合實現物件的持久化、跨進程/跨機器傳遞、快照備份等場景。

為什麼需要序列化?

  • 持久化:物件圖直接寫入文件/資料庫,避免手寫 CRUD 映射代碼。
  • 跨境傳輸:ASP.NET Session State、Remoting、gRPC、Message Queue、剪貼板皆需序列化。
  • 深度複製**:`Serialize → Deserialize` 獲得完全獨立的物件圖副本。
  • 工作流/異步處理:工作流引擎需將狀態物件序列化存儲,下次載入繼續執行。

.NET 序列化機制核心規則

  1. 類別必須標記 [Serializable] 屬性(JSON 除外)。
  2. 所有**引用的物件**也必須可序列化,否則拋出 `SerializationException`。
  3. 序列化引擎自動處理**物件圖循環引用**(追蹤已序列化物件 ID)。
  4. 預設序列化**所有實例欄位**(含 `private`),`static`、常數、`[NonSerialized]` 標記的欄位**不**序列化。
  5. 反序列化時**不調用構造函數**,直接分配記憶體並填充欄位值。

方案一:XML 序列化 (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張三

適用場景

  • 配置文件、Web Service (ASMX 舊版)、與非 .NET 系統交換數據。
  • 需人工編輯/審計的數據導出。

方案二:二進制序列化 (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 完整還原

替代方案

  • System.Text.Json / Newtonsoft.Json:安全、高效、跨平台、支援多型(配合 `$type`)。
  • protobuf-net:二進制、極致效能、嚴格契約、適合高頻 RPC。
  • MessagePack:二進制、類 JSON 結構、零拷貝解析。

方案三:JSON 序列化 (現代首選)

System.Text.Json (.NET Core 3.0+ 內建)

using System.Text.Json;

var json = JsonSerializer.Serialize(user, new JsonSerializerOptions { WriteIndented = true });
// {"Id":1,"Name":"張三"}

var u2 = JsonSerializer.Deserialize(json);
// 支援不可變類型、record、介面多型(需配置)

Newtonsoft.Json (Json.NET) — 功能最全

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 vs XML 對比

維度JSONXML
體積小 (~30-50%)大(標籤開銷)
解析速度快慢
可讀性高中
私有欄位可選(需配置)不支援
多型支援強($type / TypeNameHandling)弱
流式處理支援 (Utf8JsonReader)支援 (XmlReader)

方案四:DataContractSerializer (WCF/服務契約)

支援私有欄位、版本容忍、介面多型,需標記 `[DataContract]`、`[DataMember]`。

[DataContract]
public class User {
    [DataMember] public int Id { get; set; }
    [DataMember] public string Name { get; set; }
    [DataMember] private string _pwd; // 私有也可序列化
}

特殊場景:WinForms/WPF 自定義控件序列化

痛點:控件繼承 `Control` → `Component` → `MarshalByRefObject`,**無法直接序列化**(綁定視窗句柄、非托管資源、線程親和性)。

解決方案:記憶類模式 (DTO 分離)


// 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 (預設首選)

最佳實踐清單

  1. DTO 分離:領域模型 ≠ 序列化模型,避免循環引用、敏感數據洩露、UI 耦合。
  2. 版本容忍:新增欄位預設值、`[OptionalField]`、避免刪除/重命名欄位。
  3. 安全第一**:拒絕反序列化非信任二進制/JSON(`TypeNameHandling=Auto` 需謹慎),驗證輸入大小、深度。
  4. 效能基準**:熱路徑用 `System.Text.Json` + `Utf8JsonWriter`/`Reader` 零分配模式。
  5. 測試往返**:單元測試覆蓋 `Serialize → Deserialize → Assert Equals`,含 null、空集合、特殊字符。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved