問題 §
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の評価が跳ね上がった」