JSON サンプルから C# クラスを生成する方法

API レスポンス、設定ファイル、Webhook のボディなどの JSON サンプルを貼り付けると、それに対応する C# クラスを書き出します。オブジェクトの形ごとに 1 クラス、public プロパティと { get; set; } アクセサーを持ち、コピーできる 1 つのファイルにまとまります。変換はブラウザー内で実行され、入力がアップロードされることはなく、読み込み後はオフラインでも動作します。

プロパティ名はすべて有効な C# 識別子になります。予約語と衝突するキーは verbatim 識別子(@class)として書き出し、C# が受け付けない文字を含むキーは作り直したうえで、元のキーを [JsonPropertyName] 属性に残すので System.Text.Json でもマッピングできます。型・クラス名・入れ子は貼り付けたサンプルから推論するため、結果は完成したモデルではなく確認すべき下書きです。

  1. 上の入力欄に JSON を貼り付けるか入力します。コメントも使えます。プロパティの上に単独で置いた // または /* */ の行は、生成されるクラスの /// <summary> 行になります。
  2. 「C# クラスを生成」を押します。下に C# 文法で色分けされたファイルが表示され、上のメッセージが実行の完了か、処理を止めた行番号を知らせます。
  3. 「C# クラスをコピー」を押すと色なしのコードがクリップボードに入るので、プロジェクトの .cs ファイルに貼り付けます。
  4. 値が合わないときは JSON を編集して再生成します。前回の結果は失敗した実行も含めて毎回消えるため、コピーした内容は常に現在の入力に対応します。

値・キー・配列が C# になるまで

JSON の値がどの C# 型になるか

数値は範囲で型を決めます。Int32 に収まる整数は int、それより大きい整数は 2^53 まで long、小数があるものやそれを超えるものは double になるので、2147483648 や 1e10 が int になることはもうありません。true と false は bool、サンプル内で常に null の値は string になります。文字列は string のままですが、日付の形をしていて日付として解釈できる場合は DateTime になります。2024-05-06、2024/05/06 10:00、12/31/2024、May 6, 2024 は DateTime になり、20240506、1-2、R2D2、数値 ID は元の文字列のままです。

同じフィールドが配列の要素ごとに違う値型を持つ場合、数値はより広い型が優先され(int と long なら long、int と 2.5 なら double)、それ以外の不一致は object になります。ある要素で null、別の要素で型がある場合は null でない要素の型を採用するため、1 つの null が他の行の情報を消すことはありません。

JSON のキーが C# プロパティになるまで

C# が許す限り、プロパティは JSON のキーをそのまま保ちます。予約語のキーは verbatim 識別子として書くので、class は @class になり、コンパイルでき、同名のキーにも引き続きマッピングされます。C# が受け付けない文字を含むキーは作り直します。user-name は userName、first name は firstName、1st は _1st、a.b は aB、空のキーは value になります。同じ識別子に集約される 2 つのキーは上書きせず数値サフィックスを付けるため、a.b と a&b は aB と aB2 になります。

プロパティ名が JSON キーと異なる場合は [JsonPropertyName("...")] を付け、ファイルに using System.Text.Json.Serialization を追加します。プロパティ名を繰り返すだけの場合は属性を省略し、class のような予約語のキーは verbatim 名がすでに一致するため不要です。この属性がファイルに書かれる唯一の設定で、シリアライザー設定もスキーマも、変更していないキーの注釈もありません。

オブジェクト・配列・入れ子のクラス

異なるオブジェクトの形ごとに 1 クラスを作り、JSON キーを PascalCase にした名前を付けます。同じファイル内で名前は重複しません。2 つ目の data は Data2、wrap の中の data は WrapData になるので、2 つの枝がともに Data を名乗ることはもうありません。ファイル自身が使う型(List、String、Object、DateTime)をクラス名にすると隠蔽されるため、その名前も避けます。メンバーが自分のクラス名を繰り返すこともありません。

配列は最初の要素だけでなく全体を読みます。[1, 2, 3] は List<int>、[1, 2.5] は List<double>、オブジェクトの配列は、どの要素かに現れるキーをすべて持つ 1 つの統合クラスのリストになり、オブジェクトとスカラーが混在する配列は List<object> になります。空の配列はプレースホルダーとして List<string> になります。ルートのオブジェクトは常に Root という名前で、ルートが配列の場合はコメントで明記し、統合した要素からモデル化します。ルートがスカラーの場合はプロパティを推論できなかった旨のコメント付きの空クラスを生成します。

生成されるファイルと、そうでないもの

出力は 1 つの C# ソースファイルです。生成時刻のコメント、そのファイルに本当に必要な using ディレクティブ、そしてクラスが並びます。{ get; set; } プロパティだけの素の C# で、コンストラクターも namespace もないため、.NET Core 3.0 以降のプロジェクトにそのまま持ち込めます。ここでコンパイルは行わず、ページはテキストを書き出すだけです。

型は貼り付けた 1 つのサンプルから決まるため、サンプルで常に 0 のフィールドは、本番が小数を送っていても int になります。たまたま空だった配列は List<string> になります。結果は下書きとして扱い、依存する型を確認し、ルートクラスは好きな名前に変え、サンプル内の JSON コメントは残してください。コメントだけがドキュメントになる唯一の入力です。

最近使ったツール: