目次
概要
.NET 標準ライブラリである System.Text.Json を使用して、C#のオブジェクトをJSON文字列に変換(シリアライズ)したり、その逆(デシリアライズ)を行ったりする方法です。 日本語を含む文字列の文字化け(Unicodeエスケープ)防止や、キャメルケース(先頭小文字)への自動変換、整形表示(Pretty Print)などの実践的な設定を含めた実装を紹介します。
仕様(入出力)
- 入力: C#のデータオブジェクト(日本語を含むプロパティあり)。
- 出力: 整形されたJSON文字列、およびJSONから復元されたオブジェクトの内容。
- 前提: .NET Core 3.1 以上(推奨は .NET 6.0 以上)。標準ライブラリのみ使用。
基本の使い方
最もシンプルな形での変換です。オプションを指定しない場合、プロパティ名はそのまま(PascalCase)、日本語はエスケープされる場合があります。
var data = new { Name = "Data", Value = 100 };
// オブジェクト -> JSON
string json = JsonSerializer.Serialize(data);
// JSON -> オブジェクト
var result = JsonSerializer.Deserialize<ExpectedType>(json);
コード全文
ここでは「書籍データ」を扱うシナリオで、以下の要件を満たすコードを提示します。
- 日本語対応:
JavaScriptEncoderを指定し、日本語を\uXXXX形式にエスケープさせない。 - キャメルケース: C#の
Titleプロパティを JSONではtitleに変換する。 - 整形: JSONを見やすく改行・インデントする。
- 除外: 特定のプロパティ(内部管理IDなど)をJSONに出力しない。
using System;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
public class Program
{
public static void Main()
{
// 1. シリアライズ対象のデータ作成
var book = new Book
{
Title = "C#プログラミング入門",
PublishDate = new DateTime(2025, 1, 15),
IsAvailable = true,
InternalCode = "SECRET_123" // これはJSONに出力したくない
};
// 2. シリアライズ設定(オプション)
var options = new JsonSerializerOptions
{
// 日本語をUnicodeエスケープ(\uXXXX)せずそのまま出力する設定
Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
// プロパティ名をキャメルケース(camelCase)に変換する (Title -> title)
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// JSONを読みやすくインデント付きで出力する
WriteIndented = true
};
Console.WriteLine("--- 1. シリアライズ (Object -> JSON) ---");
// 変換実行
string jsonString = JsonSerializer.Serialize(book, options);
Console.WriteLine(jsonString);
Console.WriteLine("\n--- 2. デシリアライズ (JSON -> Object) ---");
// 復元実行
// 外部から受け取ったJSON文字列をオブジェクトに戻す
Book? deserializedBook = JsonSerializer.Deserialize<Book>(jsonString, options);
if (deserializedBook != null)
{
Console.WriteLine($"タイトル: {deserializedBook.Title}");
Console.WriteLine($"出版日 : {deserializedBook.PublishDate:yyyy/MM/dd}");
Console.WriteLine($"在庫あり: {deserializedBook.IsAvailable}");
// JsonIgnoreがついているため、復元時も初期値(null/default)になる
Console.WriteLine($"管理ID : {deserializedBook.InternalCode ?? "(null)"}");
}
}
}
// データクラス定義
public class Book
{
public string Title { get; set; } = string.Empty;
public DateTime PublishDate { get; set; }
public bool IsAvailable { get; set; }
// [JsonIgnore]属性をつけると、シリアライズ/デシリアライズの両方で無視されます
[JsonIgnore]
public string? InternalCode { get; set; }
}
実行結果例
--- 1. シリアライズ (Object -> JSON) ---
{
"title": "C#プログラミング入門",
"publishDate": "2025-01-15T00:00:00",
"isAvailable": true
}
--- 2. デシリアライズ (JSON -> Object) ---
タイトル: C#プログラミング入門
出版日 : 2025/01/15
在庫あり: True
管理ID : (null)
カスタムポイント
- 大文字小文字を区別しない: デシリアライズ時に、JSON側の
titleとC#側のTitleを柔軟にマッピングしたい場合は、PropertyNameCaseInsensitive = trueを設定します。 - Enumの文字列化: 列挙型(Enum)を数値(
0,1)ではなく文字列("Red","Blue")として出力したい場合は、options.Converters.Add(new JsonStringEnumConverter())を追加します。 - 高速化: 特定の型専用のシリアライズコードをコンパイル時に生成する「Source Generator」を使用すると、パフォーマンスがさらに向上します(.NET 6.0以降)。
注意点
- プロパティのみ対象: デフォルトでは
publicな プロパティ(Getter/Setterを持つもの)のみがシリアライズされます。publicな フィールド は無視されるため、フィールドを含めたい場合はJsonInclude属性が必要です。 - 循環参照: オブジェクト同士が相互に参照し合っている場合(例: 親 -> 子 -> 親)、シリアライズ時に
JsonExceptionが発生します。ReferenceHandler.Preserveなどを設定して回避する必要があります。 - Newtonsoft.Jsonとの違い: 古くから使われている
Newtonsoft.Json (Json.NET)とは挙動が異なる部分があります(例: 文字列の引用符のエスケープ仕様や、プライベートセッターの扱いなど)。移行の際は十分なテストを行ってください。
応用
ファイルへの非同期書き込み
大量のデータを扱う場合、文字列変数に一度展開するのではなく、FileStream を使って直接ファイルに書き込むことでメモリ効率を改善できます。
// ファイルへ直接書き込む(非同期)
using (FileStream fs = File.Create("book.json"))
{
await JsonSerializer.SerializeAsync(fs, book, options);
}
// ファイルから直接読み込む(非同期)
using (FileStream fs = File.OpenRead("book.json"))
{
Book? result = await JsonSerializer.DeserializeAsync<Book>(fs, options);
}
まとめ
[JsonIgnore] などの属性を活用して、APIに公開するデータを厳密に制御してください。
.NET Core 3.0以降、標準の System.Text.Json が高パフォーマンスかつ推奨される選択肢です。
日本語を含む場合は Encoder 設定、Web APIとの連携では PropertyNamingPolicy 設定が必須級のポイントです。
