PG日誌

受託系 PG が C# の事を書いています

C# で JSON をシリアライズ、デシリアライズする

C# で JSON 形式のデータをシリアライズ・デシリアライズする方法のメモです。.NET Frameworkの標準ライブラリにあるDataContractJsonSerializer を使ってファイルやネットワークから読みとった JSON な文字列を C# のオブジェクトへ変換したり、オブジェクトの内容を JSON 文字列へ変換を行います。

Json.NETは使用しません。

データ構造

今回シリアライズ、デシリアライズするデータとクラスの構成は以下の通りです。

クラス構成

c#のクラスの内容です。

using System.Runtime.Serialization.Json;

[DataContract]
public class Person
{
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public IDictionary<string, string> Attributes { get; private set; }

    public Person()
    {
        this.Attributes = new Dictionary<string, string>();
    }
}

扱う JSON データ

クラスをシリアライズした時、もしくはデシリアライズするときに使用するデータは以下となります。

[
    {
        "ID": 0, 
        "Name": "Taka", 
        "Attribute": {
            "key1": "value1"
            "key2": "value2"
            "key3": "value3"
        }
    }, 
    {
        "ID": 1, 
        "Name": "PG", 
        "Attribute": {
            "keyAA": "valueAA"
            "keyBB": "valueBB"
            "keyCC": "valueCC"
        }
    }
]

準備

先ずはプロジェクトとコードに以下準備を行います。

(1) DataContractJsonSerializerを使用するにプロジェクトにSystem.Runtime.Serializationの参照を追加します。

(2) 使用するコードに以下using宣言を追加します。

using System.Runtime.Serialization;

(3) シリアル化対象のクラスに以下属性を指定します。

[DataContract]
public class Person

(4) 対象メンバーに以下属性を指定します。

[DataMember]
public int ID { get; set; }

補足

もしクラスと JSON でフィールドの名前が違う場合、属性にNameが指定できます。

クラス名と異なる場合

[DataContract(Name = "Taka")]
public class Person

メンバー名が異なる場合

[DataMember(Name = "key")]
public int ID { get; set; }

Note:

クラスと JSON でフィールドの名前が違う場合、属性にNameが指定できます。

リアライズ

DataContractJsonSerializerとMemoryStreamを使ってオブジェクトを JSON にシリアライズします。

public static class JsonUtility
{
    /// <summary>
    /// 任意のオブジェクトを JSON メッセージへシリアライズします。
    /// </summary>
    public static string Serialize(object graph)
    {
        using (var stream = new MemoryStream())
        {
            var serializer = new DataContractJsonSerializer(graph.GetType());
            serializer.WriteObject(stream, graph);
            return Encoding.UTF8.GetString(stream.ToArray());
        }
    }
}

使い方

使い方はこんな感じです。

static void Main(string[] args)
{
    // データの作成
    var p_1 = new Person()
    {
        ID = 0,
        Name = "Taka",
    };
    p_1.Attributes.Add("key1", "value1");
    p_1.Attributes.Add("key2", "value2");
    p_1.Attributes.Add("key3", "value3");

    var p_2 = new Person()
    {
        ID = 1,
        Name = "PG",
    };
    p_2.Attributes.Add("keyAA", "valueAA");
    p_2.Attributes.Add("keyBB", "valueBB");
    p_2.Attributes.Add("keyCC", "valueCC");

    // リストに設定する
    List<Person> pList=new List<Person>() { p_1, p_2 };

    // リストをデシリアライズ
    string json = JsonUtility.Serialize(pList);

    // 内容をコンソールへ表示
    Console.WriteLine(json);
}

これで冒頭の JSON の例と同じ値が出力されます。

デシリアライズ

今度はデシリアライズです。

public static class JsonUtility
{
    /// <summary>
    /// Jsonメッセージをオブジェクトへデシリアライズします。
    /// </summary>
    public static T Deserialize<T>(string message)
    {
        using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(message)))
        {
            //var setting = new DataContractJsonSerializerSettings()
            //{
            //    UseSimpleDictionaryFormat = true,
            //};
            var serializer = new DataContractJsonSerializer(typeof(T), /*setting*/);
            return (T)serializer.ReadObject(stream);
        }
    }
}

使い方

先ほどの例でシリアライズしたメッセージが JSON に入っている状態から以下のようにデシリアライズします。

static void Main(string[] args)
{
    // ...前略...

    // デシリアライズ
    var pDeserializeList = JsonUtility.Deserialize<IList<Person>>(json);

    // 内容の出力
    foreach (var p in pDeserializeList)
    {
        Console.WriteLine("ID = " + p.ID);
        Console.WriteLine("Name = " + p.Name);
        foreach (var att in p.Attributes)
        {
            Console.WriteLine(att.Key + " = " + att.Value);
        }
    }
}

DataContractJsonSerializerSettingsについて

DataContractJsonSerializerSettingsのUseSimpleDictionaryFormatは指定方法によってDictionaryのデータ形式の取り扱い方法が若干変わります。それぞれ動作を確認した結果は以下に載せておきます。

UseSimpleDictionaryFormat = trueの場合

trueの場合、任意のキーと任意のValueがDictionaryの値になります。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": {
            "key1": "value1",
            "key2": "value2",
            "key3": "value3"
        }
    },
    {
        "ID": 1,
        "Name": "PG",
        "Attributes": {
            "keyAA": "valueAA",
            "keyBB": "valueBB",
            "keyCC": "valueCC"
        }
    }
]

UseSimpleDictionaryFormat = falseの場合

false(もしくは設定しない)の場合、Key=“”, Value=“"のペアの繰り返しの配列扱いになります。多分こっちはあんまり使わないのですが、状況によってどうするか変わると思います。

[
    {
        "ID": 0,
        "Name": "Taka",
        "Attributes": [
            {
                "Key": "key1", 
                "Value": "value1"
            }, 
            {
                "Key": "key2", 
                "Value": "value2"
            }, 
            {
                "Key": "key3", 
                "Value": "value3"
            }
        ]
    },
    {
        "ID": 1, 
        "Name": "PG",
        "Attributes": [
            {
                "Key": "keyAA", 
                "Value": "valueAA"
            },
            {
                "Key": "keyBB", 
                "Value": "valueBB"
            },
            {
                "Key": "keyCC", 
                "Value": "valueCC"
            }
        ],
    }
]

コード全体

上記コード全体をGistにアップアップしました。 良かったら見てください。

JsonUtility.cs · GitHub