在 System.Text.Json 中的反射與源代碼生成

本文說明反映與來源產生之間的差異,因為它與 System.Text.Json 串行化有關。 它也提供如何為您的案例選擇最佳方法的指引。

元數據集合

若要序列化或還原序列化類型,JsonSerializer 需要有關如何存取型別成員的資訊。 JsonSerializer 需要下列資訊:

  • 如何存取屬性取值器和欄位以進行序列化。
  • 如何存取反序列化的建構函式、屬性設定器和欄位。
  • 有關用來自定義序列化或反序列化的屬性的信息。
  • 執行時配置來自 JsonSerializerOptions。

這項資訊稱為 元數據。

反射

預設情況下,透過 JsonSerializer反射在執行時收集元資料。 每當 JsonSerializer 第一次必須序列化或反序列化某類型時,它會收集並快取此元數據。 元數據收集程式需要時間並使用記憶體。

源代碼生成

作為替代方式,System.Text.Json 也可以使用 C# 來源產生功能來改善效能、減少私人記憶體用量,以及輔助組件調整,以降低應用程式大小。 此外,某些反映 API 無法在 原生 AOT 應用程式中使用,因此您必須針對這些應用程式使用來源產生。

來源產生可用於兩種模式:

  • 元數據型模式

    在編譯期間,收集串行化所需的資訊, System.Text.Json 併產生原始碼檔案,以填入所要求類型的 JSON 合約元數據。

  • 串行化優化 (快速路徑) 模式

    JsonSerializer 自定義串行化輸出的功能,例如命名原則和參考保留,會產生效能額外負荷。 在串行化優化模式中,System.Text.Json 產生優化的串行化代碼,直接使用 Utf8JsonWriter。 此優化或 快速路徑程式 程式碼會增加序列化吞吐量。

    目前無法使用快速路徑 反序列化 。 如需詳細資訊,請參閱 dotnet/runtime 問題 55043。

System.Text.Json 的來源產生需要 C# 9.0 或更新版本。

Note

F# 歧視工會支援僅在反射模式下有效。 它需要動態程式碼和未修剪的反射元資料。 你無法將它與原始碼生成或 Native AOT 一起使用。 欲了解更多資訊,請參閱 F# 歧視工會。

功能比較

根據每個模式所提供的下列優點,選擇反映或來源產生模式:

優點 反射 源代碼生成
(元數據型模式)
源代碼生成
(串行化優化模式)
程式代碼更簡單。 ✔️ ❌ ❌
偵錯更簡單。 ❌ ✔️ ✔️
支援在非公用成員上使用 [JsonInclude]。 ✔️ ✔️* ✔️*
支援所有可用的串行化自定義。 ✔️ ❌ † ❌ †
減少啟動時間。 ❌ ✔️ ✔️
減少私人記憶體使用量。 ❌ ✔️ ✔️
消除了運行時反射。 ❌ ✔️ ✔️
促使安全修剪應用程式大小的縮減。 ❌ ✔️ ✔️
增加串行化輸送量。 ❌ ❌ ✔️

* 從 .NET 11 開始,原始碼產生功能支援你以 [JsonInclude] 明確標記的 private、internal 和 protected 成員。 它也支援對你以 internal 標記的屬性使用 private、protected 和 [JsonInclude] 存取子。 基於元資料的原始碼產生支援不可存取的建構器,並用 [JsonConstructor] 標記這些建構器。 產生的 setter 只會對 JSON 中出現的僅限 init 的屬性執行,因此省略的屬性會保留其初始設定值。 在 .NET 10 和更早版本中,原始碼產生不支援 private 或 protected 成員或存取子,也不支援無法存取的建構函式。 產生的上下文只有在成員與存取者共用一個組件時才能存取 internal 。 欲了解更多資訊,請參閱 私人會員與製造商。 † 使用合約自訂 API 來修改原始碼產生的合約。