2017年12月08日
川俣晶の縁側ソフトウェア技術雑記 total 4031 count

C#で使用できるJSONシリアライザで配列を扱えるかを調べる

Written By: 川俣 晶連絡先

問題 §

 JSONシリアライザで配列が正しくシリアライズされない現象に遭遇したので目に付いたシリアライザで一通りチェックしてみた。

前提条件 §

  • 確認日当日(2017/12/08)の状況である
  • DynamicJsonObjectとDynamicJsonArrayとJson.Encodeは同じモジュールに含まれている兄弟クラスである
  • Json.Encodeは下請けとしてJavaScriptSerializerを使用している (ソースコードで確認)

検証ソース §

using System;

using System.Collections.Generic;

using System.Web.Script.Serialization;

using System.Web.Helpers;

using Codeplex.Data;

using Newtonsoft.Json;

class Program

{

    static void Main()

    {

        var obj1 = new

        {

            array1 = new object[] { 123 },

            array2 = new DynamicJsonArray(new object[] { 123 })

        };

        dynamic obj2 = new DynamicJsonObject(new Dictionary<string, object>());

        obj2.array1 = new object[] { 123 };

        obj2.array2 = new DynamicJsonArray(new object[] { 123 });

        foreach (var item in new object[] { obj1, obj2 })

        {

            Console.WriteLine($"target type is {item.GetType().Name}");

            // case of JavaScriptSerializer

            JavaScriptSerializer s = new JavaScriptSerializer();

            var str = s.Serialize(item);

            Console.WriteLine($"JavaScriptSerializer: {str}");

            // case of Json.Encode

            var str2 = Json.Encode(item);

            Console.WriteLine($"Json.Encode:          {str2}");

            // case of DynamicJson

            var str4 = DynamicJson.Serialize(item);

            Console.WriteLine($"DynamicJson:          {str4}");

            // case of Newtonsoft.JSON

            var str5 = JsonConvert.SerializeObject(item);

            Console.WriteLine($"Newtonsoft.JSON:      {str5}");

        }

    }

}

  • System.Web.Helperの参照を追加
  • System.Web.Extensionの参照を追加
  • DynamicJsonをnugetで追加
  • Newtonsoft.JSONをnugetで追加

実行結果 §

target type is <>f__AnonymousType1`2

JavaScriptSerializer: {"array1":[123],"array2":[123]}

Json.Encode:          {"array1":[123],"array2":{}}

DynamicJson:          {"array1":[123],"array2":[123]}

Newtonsoft.JSON:      {"array1":[123],"array2":[123]}

target type is DynamicJsonObject

JavaScriptSerializer: {}

Json.Encode:          {"array1":{},"array2":{}}

DynamicJson:          {}

Newtonsoft.JSON:      {"array1":[123],"array2":[123]}

考察 §

  • Json.EncodeはDynamicJsonArrayを扱うことができないようだ
  • DynamicJsonObjectは配列を受け取ったときにDynamicJsonArrayに変換してしまうため、DynamicJsonObject+Json.Encodeの組み合わせだと配列すら扱えなくなってしまう
  • DynamicJsonObjectはSystem.Web.Helperを利用しないときには使われることはまずあり得ないので、シリアライズできないことは問題ではない。つまり、target type is DynamicJsonObjectのケースで正常に出力できないことは欠陥ではない

結論 §

  • この結果から見る限り、全てのケースにおいてNewtonsoft.JSONが最も優秀である
  • ほぼあり得ないケースを除外すれば、JavaScriptSerializer、DynamicJson、Newtonsoft.JSONの3者のいずれかがお勧めである
  • Json.Encodeを使う場合は、DynamicJsonObjectとDynamicJsonArrayを併用すべきではない
  • Json.Encodeは下請けにJavaScriptSerializerを呼び出しているので、Json.Encodeの利用を取りやめてJavaScriptSerializerに乗り換えても結果は大差ないと推定できる

感想 §

「なぜこんなことを調べた?」

「変な現象を突きつめたらいろいろと変な問題が出てきてね」

「君の個人的なお勧めはなんだい?」

「ここまで調べた範囲では、標準ライブラリにこだわるならJavaScriptSerializer。基本機能だけで良ければシンプルさでDynamicJson、豪華てんこ盛りが欲しければNewtonsoft.JSONが良いのではないかと感じた」

「他には何かあるかい?」

「ネットを検索するとNewtonsoft.JSONの情報が最も多く出てくるから調べやすい。でも、DynamicJsonは作者が日本人なので日本語で質問できる可能性がある。どちらが良いかは決めがたい」

「単なる個人的な印象で好感を持ったのはどれだい?」

「やはりDynamicJsonだな。Newtonsoft.JSONは高機能すぎて迷宮に入りやすい。シンプルですぐソースを見ることができ、適応能力も意外と高いDynamicJsonの評価が跳ね上がった」