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

C#でJSON形式を外部ライブラリを使用しないでシリアライズ・デシリアライズする方法の紹介です。Json.NETは使用しません。

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

データ構造

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

扱う JSON データ

扱うJSONの形式は以下の通りです。

通常の数字、文字列、配列、リスト、ハッシュマップの5種類の変換を以下内容で検証します。

[
    {
        "id": 0,
        "name": "Taka",
        "numbers": [
            0,
            1,
            2,
            3
        ],
        "list": [
            0,
            1,
            2,
            3
        ],
        "map": [
            {
                "Key": "key1",
                "Value": "value1"
            },
            {
                "Key": "key2",
                "Value": "value2"
            },
            {
                "Key": "key3",
                "Value": "value3"
            }
        ]
    },
    {
        "id": 1,
        "name": "PG",
        "numbers": [
            10,
            11,
            12,
            13
        ],
        "list": [
            10,
            11,
            12,
            13
        ],
        "map": [
            {
                "Key": "keyAA",
                "Value": "valueAA"
            },
            {
                "Key": "keyBB",
                "Value": "valueBB"
            },
            {
                "Key": "keyCC",
                "Value": "valueCC"
            }
        ]
    }
]

クラス構成

JSONに対応するクラスの定義をします。

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

[DataContract]
public class Person
{
    [DataMember(Name = "id")]
    public int ID { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    // 配列
    [DataMember(Name = "numbers")]
    public int[] Numbers { get; set; }

    // リスト型
    [DataMember(Name = "list")]
    public List<int> NumberList { get; private set; } = new List<int>();

    // ハッシュマップ型
    [DataMember(Name = "map")]
    public IDictionary<string, string> Attributes { get; private set; } = new Dictionary<string, string>();
}

準備

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

(1) DataContractJsonSerializerを使用するにプロジェクトにSystem.Runtime.Serializationの参照を追加します。(.NET Coreでは必要ありません

(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が指定できます。

シリアライズ

オブジェクト → JSON の変換です。

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

using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

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.Numbers = new int[] { 0, 1, 2, 3 };

    p_1.NumberList.Add(0);
    p_1.NumberList.Add(1);
    p_1.NumberList.Add(2);
    p_1.NumberList.Add(3);

    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.Numbers = new int[] { 10, 11, 12, 13 };

    p_2.NumberList.Add(10);
    p_2.NumberList.Add(11);
    p_2.NumberList.Add(12);
    p_2.NumberList.Add(13);

    p_2.Attributes.Add("keyAA", "valueAA");
    p_2.Attributes.Add("keyBB", "valueBB");
    p_2.Attributes.Add("keyCC", "valueCC");

    // Personのリストを作成する
    var pList = new List<Person>() { p_1, p_2 };

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

    // 内容をコンソールへ表示(ファイルへの保存は別途行う
    Console.WriteLine(json);
}

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

デシリアライズ

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

using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

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)
{
    // ファイルから読み取る
    string path = @"C:\Users\Taka\Desktop\sample.json";
    string body = File.ReadAllText(path);

    // デシリアライズ
    IList<Person> pDeserializedList = JsonUtility.Deserialize<IList<Person>>(body);

    // 内容の出力
    foreach (Person p in pDeserializedList)
    {
        Console.WriteLine("ID = " + p.ID);
        Console.WriteLine("Name = " + p.Name);
        foreach (KeyValuePair<string, string> 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