9

JSONにシリアル化されたジェネリックディクショナリオブジェクトを返すWCFサービスを構築することを計画しています。残念ながら、オブジェクトは常に異なる可能性があるため、シリアル化は失敗します。プロパティタイプがDictionaryであるため、KnownTypesは役に立ちません。また、クラスは常に異なる可能性があるため、KnownTypeとは言えません。

「不明なタイプ」をシリアル化できるかどうかについて何かアイデアはありますか?

クラスごとにDataContract/DataMemberを指定してもかまいませんが、(少なくともプロトタイプバージョンでは)すべての応答に強力な型を設定したくありません。Javascriptクライアントは気にしません。

匿名のクラスはどうですか?

4

2 に答える 2

7

注:回答の冒頭で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に挿入する必要のあるすべてのタイプを制御する場合は、最も簡単なことを試すことができます。

  1. 静的メソッドを使用してクラスを作成し、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();
        }
    }
  2. タイプをレジスターに登録する静的コンストラクターを追加します。

    [DataContract]
    パブリッククラスの人
    {{
        静的Person()
        {{
            KnowTypeRegister.Add(typeof(Person));
        }
        [DataMember]
        public string Name {get; セットする; }
        [DataMember]
        public int Age {get; セットする; }
    }
  3. シリアライザーを作成するときに、レジスターから既知のタイプの配列を取得します。

var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());

より動的/より優れたオプションが可能ですが、実装がより困難です。動的な既知の型の解決について詳しく知りたい場合は、このトピックに関するJuvalLowyのMSDN記事を参照してください。また、 Carlos Figueiraによるこのブログ投稿では、型を動的に生成するなどのより高度な手法についても詳しく説明しています。このトピックについては、一読する価値があります。

于 2012-04-29T01:02:43.163 に答える
1

免責事項objectWCFエンドポイントで公開することはお勧めしません。これは「柔軟」に見えますが、サービスによって提供される情報の種類を指定していないため、これはお勧めできません。

そして今答えのために

WCF呼び出しがajax呼び出しによって消費されている場合、それを入力Javascript client just doesn't care.すると、WCF呼び出しで文字列を返すだけでよいのではないでしょうか。次に、WCF呼び出しの内部でDictionary<string, object>、JavaScriptSerializerを使用してシリアル化できます。

public string MyServiceMethod()
{
    var hash = new Dictionary<string, object>();
    hash.Add("key1", "val1");
    hash.Add("key2", new { Field1 = "field1", Field2 = 42});
    var serialized = new JavaScriptSerializer().Serialize(hash);
    return serialized;
}

disclaimer2これは目的を達成するための手段です(質問をしたので)-本番品質のアプリケーションの場合、インターフェイスが明確に定義されているので、何が要求され、ネットワーク経由で返送されているかが明確になります。

于 2012-04-26T13:21:11.913 に答える