前回の記事では、.NET 8 における標準ライブラリ System.Text.Json
を使って、オブジェクトをJSON文字列にシリアライズする方法をご紹介しました。
今回はその逆、JSON文字列をC#のオブジェクトに変換する「デシリアライズ」の方法について詳しく解説していきます。
たとえば、Web APIから受け取ったJSONレスポンスを自分のアプリケーションで扱いやすくするには、JSON文字列をC#のクラスに変換する必要があります。そのときに使えるのが、JsonSerializer.Deserialize<T>()
メソッドです。
基本のデシリアライズ:JSONをオブジェクトに変換する
まず、基本の Person
クラスから復習です:
public record Person
{
public int Id { get; set; }
public string Name { get; set; }
}
このクラスに対応するJSON文字列が以下のようにあるとしましょう。
{"Id":1,"Name":"Taro"}
これをC#でデシリアライズするには、以下のように書きます。
using System.Text.Json;
string json = "{\"Id\":1,\"Name\":\"Taro\"}";
Person? person = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine($"{person?.Id}, {person?.Name}");
出力:
1, Taro
非常に簡単ですね。JSON文字列が有効なフォーマットで、対応するクラスが存在すれば、すぐにデシリアライズできます。
プロパティ名が小文字(camelCase)のJSONをデシリアライズする
JavaScriptなど他言語では、プロパティ名が小文字(camelCase)であることが多いです。以下のようなJSON:
{"id":2,"name":"Jiro"}
の場合、C#のクラスではPascalCase(Id, Name)で定義しているので、そのままではプロパティにマッピングされません。
このような場合は、JsonSerializerOptions
を使ってネーミングポリシーを設定します。
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true // 大文字小文字を無視
};
string json = "{\"id\":2,\"name\":\"Jiro\"}";
var person = JsonSerializer.Deserialize<Person>(json, options);
Console.WriteLine($"{person?.Id}, {person?.Name}");
出力:
2, Jiro
これで、camelCaseなJSON文字列にも柔軟に対応できます。
配列のデシリアライズ
複数の Person
オブジェクトが入ったJSON配列をデシリアライズすることも可能です。
以下のJSONを用意します:
[
{"Id":1,"Name":"Taro"},
{"Id":2,"Name":"Jiro"}
]
この配列をデシリアライズしてみましょう。
string jsonArray = "[{\"Id\":1,\"Name\":\"Taro\"},{\"Id\":2,\"Name\":\"Jiro\"}]";
var people = JsonSerializer.Deserialize<Person[]>(jsonArray);
foreach (var p in people!)
{
Console.WriteLine($"{p.Id}, {p.Name}");
}
出力:
1, Taro
2, Jiro
もちろん、List<Person>
として受け取ることも可能です:
List<Person>? peopleList = JsonSerializer.Deserialize<List<Person>>(jsonArray);
ネストされたオブジェクトのデシリアライズ
次に、オブジェクトの中に配列があるような、入れ子構造のJSONの例を見てみましょう。
{
"GroupId": 1,
"People": [
{ "Id": 1, "Name": "Taro" },
{ "Id": 2, "Name": "Jiro" }
]
}
このJSONに対応する Group
クラスを以下のように定義します:
public record Group
{
public int GroupId { get; set; }
public Person[] People { get; set; }
}
そして、デシリアライズします。
string json = @"
{
""GroupId"": 1,
""People"": [
{ ""Id"": 1, ""Name"": ""Taro"" },
{ ""Id"": 2, ""Name"": ""Jiro"" }
]
}";
var group = JsonSerializer.Deserialize<Group>(json);
Console.WriteLine($"Group ID: {group?.GroupId}");
foreach (var p in group?.People!)
{
Console.WriteLine($"- {p.Id}, {p.Name}");
}
出力:
Group ID: 1
- 1, Taro
- 2, Jiro
このように、入れ子になった構造でも、クラス構造を合わせれば問題なくデシリアライズできます。
JsonPropertyName属性を使ったマッピング
シリアライズと同じように、デシリアライズ時にも [JsonPropertyName]
属性を使ってJSONとクラスのプロパティ名をマッピングできます。
public record Person
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
JSONが {"id":3,"name":"Saburo"}
のようになっていても、以下のようにスムーズに読み取れます:
string json = "{\"id\":3,\"name\":\"Saburo\"}";
var person = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine($"{person?.Id}, {person?.Name}");
デシリアライズの失敗と例外処理
もしJSONが不正な形式だったり、クラスとマッピングが合っていなかった場合、JsonSerializer.Deserialize
は JsonException
をスローします。
例:
string invalidJson = "{\"Id\": \"NotAnInt\", \"Name\": \"Taro\"}";
try
{
var person = JsonSerializer.Deserialize<Person>(invalidJson);
}
catch (JsonException ex)
{
Console.WriteLine("デシリアライズに失敗しました: " + ex.Message);
}
nullの扱いに注意
Deserialize<T>
は、デフォルトで null
を返す可能性があります。値を安全に扱うためには null
チェックを必ず行いましょう。
パフォーマンスとセキュリティの注意点
- デシリアライズ対象のJSONは信頼できるソースからのみ受け取るべきです。攻撃者が意図的に破壊的なJSONを送信してくるケースがあります。
System.Text.Json
はNewtonsoft.Json
より高速ですが、一部の特殊なフォーマット(例:JSON Path、型ヒント付きのポリモーフィズム)には対応していない場合があります。
まとめ
.NET 8 では System.Text.Json
を使うことで、非常にシンプルかつ高速にJSONをデシリアライズできます。
JsonSerializer.Deserialize<T>()
を使って文字列からオブジェクトを生成- プロパティ名がcamelCaseでも
JsonSerializerOptions
やJsonPropertyName
を使えば対応可能 - 配列やネスト構造も簡単にデシリアライズ可能
- nullチェックと例外処理も忘れずに
標準ライブラリだけでここまでできるのは嬉しいですね。JSON APIとやり取りするアプリケーションを作るなら、ぜひ System.Text.Json
を活用しましょう!
コメントを残す