﻿# 如何讓 System.Text.Json 支援 Dynamic 型別的序列化/反序列化

我最近因為支援 [Quicktype](https://quicktype.io/) 開源專案，新增了 System.Text.Json (C#) 的程式碼產生器功能，因此更加理解 [System.Text.Json](https://learn.microsoft.com/zh-tw/dotnet/api/system.text.json) 的 [Converter](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to) 撰寫方式。在這之前，我其實我都還是偏好使用 [Newtonsoft.Json](https://www.newtonsoft.com/json) (俗稱 `Json.NET`) 來進行 JSON 的序列化/反序列化工作，原因就在於 Json.NET 有很多「方便」又「豐富」的功能與特性在 `System.Text.Json` 都找不到，因此剛入門 `System.Text.Json` 的人一定會覺得綁手綁腳，很多原本能動的 Code 都不能 Run 了。今天這篇文章，我打算來分享如何讓 `System.Text.Json` 支援 [dynamic](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic) 動態型別，讓你可以用「弱型別」的方式操作靈活的 JSON 資料。

![Converter](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/33b55f9a119a7a3197b0-173181002-9c80ef1e-a8c6-4451-b793-f4520b7371cd.jpg)

### 使用方式

我參考自[這篇](https://github.com/dotnet/runtime/issues/29690#issuecomment-571969037)的原始碼進行優化，自行開發出這份更加完整的 `DynamicJsonConverter` 類別，可以相當漂亮的支援**動態型別**。

1.  下載我寫的 [DynamicJsonConverter](https://gist.github.com/doggy8088/995a28b2655ec9529414c3df18aaa28e) 類別
    
2.  在主程式中建立一個 `JsonSerializerOptions` 物件並加入 `DynamicJsonConverter`
    
    ```csharp
    var serializerOptions = new JsonSerializerOptions
    {
        Converters = { new DynamicJsonConverter() }
    };
    ```
    
3.  測試 `dynamic` 轉換過程
    
    ```csharp
    // 載入任意 JSON 文字檔內容
    var jsonText = File.ReadAllText("sample.json");
    
    dynamic obj = JsonSerializer.Deserialize<dynamic>(jsonText, serializerOptions);
    
    // 存取物件的方式
    // obj.name
    // obj.batters.batter[0].id
    // obj.batters.batter[0].type
    
    string json = JsonSerializer.Serialize(obj, serializerOptions);
    ```
    

### 完整程式碼

我的完整實作都放在 Gist 上面，大家可以自行參閱程式碼進行驗證、調整、修改，有任何能夠改進的地方，也歡迎給我回饋！ 👍

> [https://gist.github.com/doggy8088/995a28b2655ec9529414c3df18aaa28e](https://gist.github.com/doggy8088/995a28b2655ec9529414c3df18aaa28e)

### 相關討論

昨天 (2022/6/10) 在我的 [台灣 .NET 技術愛好者俱樂部](https://www.facebook.com/groups/DotNetUserGroupTaiwan/) 社團中[有篇貼文](https://www.facebook.com/groups/DotNetUserGroupTaiwan/posts/2908806092745823/)有著相當豐富的討論，底下我整理一些有用的參考連結，方便大家學習：

-   討論主角
    -   [System.Text.Json](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-overview)
    -   [Json.NET - Newtonsoft](https://www.newtonsoft.com/json) ([GitHub](https://github.com/JamesNK/Newtonsoft.Json))
-   升級指南
    -   [Migrate from Newtonsoft.Json to System.Text.Json - .NET | Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to)
-   效能比較
    -   [Try the new System.Text.Json APIs - .NET Blog](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/?WT.mc_id=DT-MVP-4015686)
    -   [Try the new System.Text.Json source generator - .NET Blog](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/?WT.mc_id=DT-MVP-4015686)
-   轉換器範例
    -   [DateOnlyConverter.cs](https://gist.github.com/doggy8088/14af407600fdbf32c9ded58a02150949)
    -   [TimeOnlyConverter.cs](https://gist.github.com/doggy8088/c48beb1b45d67fe7777547794b88b6f9)
    -   [DynamicJsonConverter.cs](https://gist.github.com/doggy8088/995a28b2655ec9529414c3df18aaa28e)

### 相關連結

-   [Support "dynamic" and writable DOM · Issue #29690 · dotnet/runtime](https://github.com/dotnet/runtime/issues/29690)
-   [How to write custom converters for JSON serialization (marshalling) in .NET](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to)
-   [.NET Core 3.0 JsonSerializer.Deserialize to dynamic object](https://github.com/dotnet/runtime/issues/29690#issuecomment-571969037)
-   [Using type dynamic - C# Programming Guide | Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic)
-   [System.Text.Json 命名空間](https://learn.microsoft.com/zh-tw/dotnet/api/system.text.json)
