跳至內容

JSON 轉 C#

從 JSON 範例生成附屬性的 C# 類別。

輸入

這個工具的用途

從 JSON 樣本產生帶序列化 attribute 的 C# class。 使用 namespace 選項把產生的型別歸入你的專案命名空間。預設 輸出針對 Newtonsoft.Json(JsonProperty);相同形狀也能用 於 System.Text.Json——只需替換 attribute 名稱。底層使用 quicktype,完全在你的瀏覽器內運作。

使用步驟

貼上 JSON(或載入範例),即可在右側讀到 C# class。在選項面板設定 namespace,檔案可直接落入你的專案;預設輸出採用 Newtonsoft.Json attribute。

輸入: {"id":42,"name":"devsmiths","createdAt":"2024-03-11T08:24:00Z","stars":1280,"public":true,"contributors":[{"login":"ada","commits":51,"admin":true},{"login":"linus","commits":33,"admin":false}],"homepage":null}

輸出(C#):

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace Devsmiths
{
    public partial class Root
    {
        [JsonProperty("id")] public long Id { get; set; }
        [JsonProperty("name")] public string Name { get; set; }
        [JsonProperty("createdAt")] public string CreatedAt { get; set; }
        [JsonProperty("stars")] public long Stars { get; set; }
        [JsonProperty("public")] public bool Public { get; set; }
        [JsonProperty("contributors")] public Contributor[] Contributors { get; set; }
        [JsonProperty("homepage")] public object Homepage { get; set; }
    }

    public partial class Contributor
    {
        [JsonProperty("login")] public string Login { get; set; }
        [JsonProperty("commits")] public long Commits { get; set; }
        [JsonProperty("admin")] public bool Admin { get; set; }
    }
}

限制與邊界情況

  • 預設輸出針對 Newtonsoft.Json(JsonProperty)。 要切到 .NET 6+ 的 System.Text.Json,只需 find/replace:JsonPropertyJsonPropertyNameusing Newtonsoft.Json using System.Text.Json.Serialization——屬性形狀完全相同。
  • 屬性是 public 自動屬性(get; set;), 不是 records。C# 9+ records 形狀無法靠原樣通過 System.Text.Json 來回(records 的 primary constructor 需要 [JsonConstructor] 加上排序好的參數)——對語法層產生器超出範圍。
  • Nullable reference type 沒有標記。若專案 csproj 開啟 <Nullable>enable</Nullable>,請手動為 reference type 加上 ?(或接受警告)。Value type(long bool)會自動以 ? 標示樣本中為 null 的位置。
  • 日期字串保持為 string,不是 DateTime / DateTimeOffset。ISO 8601 字串無歧義,但混用序列化 attribute 來處理日期轉換很脆弱——若需要型別化日期, 請寫自訂 JsonConverter
  • 陣列輸出為 T[] 而非 List<T>。 Newtonsoft.Json 與 System.Text.Json 都能正確反序列化兩者; 若 runtime 需要 .Add(),請手動改為 List<T>
  • 單樣本推論:樣本中缺漏的鍵不會自動變 nullable。切換 all optional 套用全部欄位。

常見問題

Newtonsoft.Json 還是 System.Text.Json — 輸出針對哪個?
預設是 Newtonsoft.Json(`[JsonProperty]` attribute、`using Newtonsoft.Json`)。Newtonsoft 較寬鬆且在 legacy 專案中較普遍。要切到 .NET 6+ 的 System.Text.Json,find/replace:`[JsonProperty("foo")]` → `[JsonPropertyName("foo")]`、`using Newtonsoft.Json` → `using System.Text.Json.Serialization`。屬性形狀完全相同。
為什麼 C# 9+ 不產生 records?
Records 看似合適(不可變、值相等、行數少),但 primary constructor 參數無法直接通過 System.Text.Json 來回——需要 `[JsonConstructor]` annotation 與精確的參數順序,容易出錯也容易悄悄錯位。產生器堅持 `public class { get; set; }` 屬性,因為兩種序列化器都能零配置來回。
如何讓 nullable reference type 與 #nullable enable 相容?
Value type(long、bool)在樣本含 null 時會自動加上 `?`。Reference type(string、object)不會——產生器輸出時不標記。若專案開啟 `<Nullable>enable</Nullable>`,請手動為可能為 null 的欄位加 `?`。產生器保守在此,因為把所有東西都標為 `string?` 會把 null check 推到呼叫端,可能不是你要的。
ISO 8601 日期字串可以變成 DateTime / DateTimeOffset 嗎?
不會自動——日期字串保持為 `string`。變通做法:把欄位型別改為 `DateTime`,讓序列化器預設的 ISO 8601 解析來處理(.NET 7+ 的 System.Text.Json 支援);或為含時區資訊的欄位寫 `JsonConverter<DateTimeOffset>`。對 wire-format 日期通常 DateTimeOffset 是正確選擇。
為什麼陣列用 T[] 而不是 List<T>?
T[] 大小固定,配置成本較低且 Span 相容;List<T> 可變但配置 overhead 較高。產生器選 T[] 是因為反序列化兩者效果相同,瘦型別是更好的預設。對需要在領域程式碼中變動的集合,可手動改為 List<T>。
JsonProperty("…") attribute 實際在做什麼?
它告訴 Newtonsoft.Json(改名後對 System.Text.Json 同樣)該屬性對應的 JSON 鍵是什麼。C# 慣例是 PascalCase 屬性名、JSON 慣例是 camelCase 或 snake_case——attribute 在兩者之間架橋。沒有它,Newtonsoft 會 fallback 到大小寫不敏感比對,通常能運作但較慢、較隱晦;明確的 attribute 更清楚也更快。

內容審閱者: