rksoftware

Visual Studio とか C# とかが好きです

C# で定義が未知の Json を扱う (.NET Framework / ExpandoObject)

未知の Json を扱う一連の記事をまとめた記事を書きました。
こちらの記事で一気読みできます。

■ 【過去】 .NET Framework 時代

Json を扱う際には .NET Framework 時代には Json.NET というライブラリがよく使われていました。
このライブラリの Newtonsoft.Json.JsonConvert.DeserializeObject メソッドで未知の Json を扱うことができました。

メソッドの定義は次のようになっています。

public static object? DeserializeObject(string value);

使う際には、dynamic 型変数に代入して使っていた方も多いのではないでしょうか? 次のように

dynamic document = Newtonsoft.Json.JsonConvert.DeserializeObject(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");
Console.WriteLine(document.prop1);  // value1 と出力される
Console.WriteLine(document.prop2);  // value2 と出力される

実際にはこの際、DeserializeObject からの戻りは何だろうと次のコードで検証した記事を以前に書きました。 結論としては、Newtonsoft.Json.Linq.JObject になっていました。まあ、そのまま使えばいいのですが、C# には実はその他に dynamic の中身として使う System.Dynamic.ExpandoObject クラスがいます。今回はこの型を使ってみましょう。

型の指定、型の確認

dynamic document = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");
Console.WriteLine(((object)document).GetType().FullName);  // System.Dynamic.ExpandoObject

System.Dynamic.ExpandoObject になりました。

プロパティを表示する

普通に dynamic っぽく。

dynamic document = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");

Console.WriteLine(document.prop1);  // value1 と出力される
Console.WriteLine(document.prop2);  // value2 と出力される

System.Dynamic.ExpandoObjectIDictionary<string, object> を実装しているので、Key と Value を foreach で回せます。

System.Dynamic.ExpandoObject document = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");

foreach (var m in document)
    Console.WriteLine($"key:{m.Key}, Value:{m.Value}");

// key:prop1, Value:value1
// key:prop2, Value:value2
// と出力される

プロパティを追加する

IDictionaryAdd メソッドでプロパティを追加できます。

System.Dynamic.ExpandoObject document = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");

((IDictionary<string, object>)document).Add("prop3", "value3");

foreach (var m in document)
    Console.WriteLine($"key:{m.Key}, Value:{m.Value}");

Console.WriteLine($"key:prop3, Value:{((dynamic)document).prop3}");
// key:prop1, Value:value1
// key:prop2, Value:value2
// key:prop3, Value:value3
// key:prop3, Value:value3
// と出力される

dynamic 型にして次のようにしてもできます。

((dynamic)document).prop3 = "value3";

プロパティを削除する

IDictionaryRemove メソッドでプロパティを削除できます。

System.Dynamic.ExpandoObject document = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(
    @"{ ""prop1"": ""value1"", ""prop2"": ""value2""}");

((IDictionary<string, object>)document).Remove("prop1");

foreach (var m in document)
    Console.WriteLine($"key:{m.Key}, Value:{m.Value}");

// key:prop2, Value:value2
// と出力される

IDictionary<string, object> を実装しているので特にキャストしなくても OK です。

document.Remove("prop1", out var _);