注:回答の冒頭でJavaScriptSerializerについて多くの詳細を説明しました。元の質問で言及されている既知のタイプの問題の解決策について読みたい場合は、回答の最後にジャンプしてください。
パフォーマンス
私が実行したベンチマークに基づくと、JavaScriptSerializerは他の選択肢よりもはるかに低速であり、DataContractSerializerと比較してオブジェクトのシリアル化/逆シリアル化に2倍の時間がかかる可能性があります。
既知のタイプは必要ありません
とは言うものの、JavascriptSerializerは、事前に「既知の型」を指定する必要がないという点でより柔軟性があり、シリアル化されたJSONは、少なくとも辞書の場合はよりクリーンです(ここの例を参照)。
既知の型に関する柔軟性の裏側は、同じJSON文字列を逆シリアル化して元の型に戻すことができないことです。たとえば、単純なPerson
クラスがあるとします。
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
そして、シリアル化する前に、のインスタンスを作成し、それにクラスDictinoary<string, object>
のインスタンスを追加すると、次のようになります。Person
var dictionary = new Dictionary<string, object>();
dictionary.Add("me", new Person { Name = "Yan", Age = 30 });
var serializer = new new JavaScriptSerializer();
var json = serializer .Serialize(dictionary);
次のJSONを取得します。{"me":{"Name":"Yan","Age":30}}
これは非常にクリーンですが、タイプ情報がありません。したがって、同じメンバー定義を持つ2つのクラスがある場合、またはPerson
追加のメンバーを導入せずにサブクラス化されている場合は、次のようになります。
public class Employee : Person
{
}
{"Name":"Yan","Age":30}
その場合、シリアライザーがJSONを正しいタイプに逆シリアル化できることを保証できる方法はありません。
JavaScriptSerializerを使用して逆シリアル{"me":{"Name":"Yan","Age":30}}
化すると、ディクショナリで「me」に関連付けられた値がインスタンスでPerson
はなくDictionary<string, object>
、単純なプロパティバッグになります。
インスタンスを元に戻したい場合は、ヘルパーメソッドを使用してPerson
インスタンスを変換できます(おそらく絶対にやりたくないでしょうが!) 。Dictionary<string, object>
ConvertToType
var clone = serializer.Deserialize<Dictionary<string, object>>(json);
var personClone = serializer.ConverToType<Person>(clone["me"]);
一方、これらのJSONを正しいタイプに逆シリアル化することを心配する必要がなく、JSONのシリアル化がパフォーマンスのボトルネックではない場合(コードのプロファイルを作成し、シリアル化に費やされたCPU時間を調べてください。すでに)それなら私はJavaScriptSerializerを使うと言うでしょう。
既知のタイプの注入
1日の終わりに、DataContractSerializerを使用する必要があり、それらの既知のタイプを挿入する必要がある場合は、次の2つの方法を試すことができます。
1)既知の型の配列をDataContractSerializerコンストラクターに渡します。
2) DataContractResolverのサブクラス(関心のあるタイプを見つける手段を使用)をDataContractSerializerコンストラクターに渡します
ディクショナリに追加できるタイプを追跡する種類の「既知のタイプレジストリ」を作成できます。DataContractSerializerに挿入する必要のあるすべてのタイプを制御する場合は、最も簡単なことを試すことができます。
静的メソッドを使用してクラスを作成し、KnownTypeRegister
既知のタイプのリストにタイプを追加します。
パブリック静的クラスKnownTypeRegister
{{
private static readonly ConcurrentBag _knownTypes = new ConcurrentBag();
public static void Add(Type type)
{{
_knownTypes.Add(type);
}
public static IEnumerable Get()
{{
return _knownTypes.ToArray();
}
}
タイプをレジスターに登録する静的コンストラクターを追加します。
[DataContract]
パブリッククラスの人
{{
静的Person()
{{
KnowTypeRegister.Add(typeof(Person));
}
[DataMember]
public string Name {get; セットする; }
[DataMember]
public int Age {get; セットする; }
}
シリアライザーを作成するときに、レジスターから既知のタイプの配列を取得します。
var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());
より動的/より優れたオプションが可能ですが、実装がより困難です。動的な既知の型の解決について詳しく知りたい場合は、このトピックに関するJuvalLowyのMSDN記事を参照してください。また、 Carlos Figueiraによるこのブログ投稿では、型を動的に生成するなどのより高度な手法についても詳しく説明しています。このトピックについては、一読する価値があります。