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

手寫高效能 JsonBuilder:300 行打造可擴展、支援循環參考的 C# 序列化器

     編輯:關於C#

為什麼要在 Newtonsoft.Json、System.Text.Json 稱霸的今天手寫序列化器?作者給出三個理由:簡單(單一類別)、輕量(300 行)、靈活(繼承覆寫單一方法即可擴展型別處理)。本文完整呈現 JsonBuilder 核心架構:以 StringBuilder 為緩衝、虛擬方法對應各基礎型別、反射處理未知物件、字典快取解決循環參考。

核心設計:虛擬方法表驅動型別處理

public class JsonBuilder {
    protected StringBuilder Buff = new StringBuilder(4096);

    public string ToJsonString(object obj) {
        Buff.Length = 0;
        AppendObject(obj);
        return Buff.ToString();
    }

    // 入口:依型別分流
    protected void AppendObject(object obj) {
        if (obj == null) { Buff.Append("null"); return; }
        if (obj is string) { AppendString((string)obj); return; }
        if (obj is int) { AppendInt32((int)obj); return; }
        // ... 其他基礎型別 ...

        // 循環參考偵測
        if (!_LoopObject.ContainsKey(obj)) {
            _LoopObject.Add(obj, null);
            if (obj is IDictionary) AppendJson((IDictionary)obj);
            else if (obj is IEnumerable) AppendArray((IEnumerable)obj);
            else if (obj is DataSet) AppendDataSet((DataSet)obj);
            else if (obj is DataTable) AppendDataTable((DataTable)obj);
            else if (obj is DataView) AppendDataView((DataView)obj);
            else AppendOther(obj); // 反射處理自訂類別
            _LoopObject.Remove(obj);
        } else {
            Buff.Append("undefined"); // 循環參考標記
        }
    }

    // 可覆寫的虛擬方法們
    protected virtual void AppendString(string v) { /* ... */ }
    protected virtual void AppendInt32(int v) { AppendNumber(v); }
    protected virtual void AppendNumber(IConvertible n) { Buff.Append(n.ToString(NumberFormatInfo.InvariantInfo)); }
    protected virtual void AppendOther(object obj) { /* 反射屬性 */ }
    // ... 陣列、字典、DataTable 等集合型別 ...
}

循環參考解法:_LoopObject 字典

遇到 A.B = A 這類循環,第一次進入 AppendObject 將物件加入 _LoopObject,遞迴處理屬性時再次遇到同物件 → 直接輸出 undefined,避免堆疊溢位。這比 Newtonsoft 預設拋例外更優雅,也能區分 null。

擴展範例:把 Enum 序列化為數值而非字串

public class EnumValueJsonBuilder : JsonBuilder {
    protected override void AppendEnum(Enum value) {
        Buff.Append(value.GetHashCode()); // 或 Convert.ToInt64(value)
    }
}

單一覆寫,全域生效——這就是「虛擬方法表」帶來的擴展力。

完整程式碼與測試圖

呼叫範例

JSON 輸出格式

// 完整 JsonBuilder 程式碼(含 DateTime、Guid、DataTable、字串逸出等細節)
// 請見原文完整代碼區塊

適用場景與取捨

  • ✅ 嵌入式裝置、AOT 編譯、不想引入大型套件
  • ✅ 需要高度客製化輸出格式(如特殊日期格式、Enum 數值化)
  • ❌ 高併發熱路徑(反射 + StringBuilder 仍慢於原生/IL 生成器)
  • ❌ 需支援複雜多型、$ref、自訂 Converter 生態系

300 行掌握序列化核心邏輯,既是造輪子練功,也是理解現有庫底層運作的最佳教材。有興趣可再往 Utf8JsonWriter、Source Generator 方向深入。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved