プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2019/04/18

[C#] Dictionary の キーがタプルの場合に JSON へのシリアライズとデシリアライズを行う方法

event_note2019/04/18 9:10

.NET で JSON へのシリアライズとデシリアライズを行う場合、Newtonsoft.Json (Json.NET) がよく使われます。

しかし、現時点の Newtonsoft.Json のバージョン (11.0.2) では、Dictionary のキーがタプルの場合のシリアライズとデシリアライズに対応できません。
この場合、.NET 標準の DataContractJsonSerializer を使用します。

環境

  • .NET Core 2.2

シリアライズ

DataContractJsonSerializer を使って通常通りシリアライズするだけです。
例として、以下のようなデータをシリアライズしてみます。

static void Main(string[] args)
{
    var SampleDataList = new Dictionary<Tuple<int, string>, string>()
    {
        [Tuple.Create(0, "Foo")] = "sample1",
        [Tuple.Create(0, "Bar")] = "sample2",
        [Tuple.Create(1, "Foo")] = "sample3",
        [Tuple.Create(2, "Bar")] = "sample4",
    };

    var serializedData = Serialize(SampleDataList);

    Console.WriteLine(serializedData);
}

static string Serialize<T>(T value)
{
    var serializer = new DataContractJsonSerializer(typeof(T));
    var serializedData = string.Empty;
    using (var memoryStream = new MemoryStream())
    {
        serializer.WriteObject(memoryStream, value);
        serializedData = Encoding.UTF8.GetString(memoryStream.ToArray());
    }

    return serializedData;
}

出力結果

以下のようになります。(見やすいように整形してあります。)

[
    {
        "Key": {
            "m_Item1": 0,
            "m_Item2": "Foo"
        },
        "Value": "sample1"
    },
    {
        "Key": {
            "m_Item1": 0,
            "m_Item2": "Bar"
        },
        "Value": "sample2"
    },
    {
        "Key": {
            "m_Item1": 1,
            "m_Item2": "Foo"
        },
        "Value": "sample3"
    },
    {
        "Key": {
            "m_Item1": 2,
            "m_Item2": "Bar"
        },
        "Value": "sample4"
    }
]

デシリアライズ

上記の JSON をデシリアライズする場合も、通常通りデシリアライズするだけです。

var deserializedData = JsonConvert.DeserializeObject<Dictionary<Tuple<int, string>, string>>(serializedData);
static T Deserialize<T>(string value)
{
    var serializer = new DataContractJsonSerializer(typeof(T));
    var deserializedData = default(T);
    using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(value)))
    {
        deserializedData = (T)serializer.ReadObject(stream);
    }
    return deserializedData;
}