15

私はDataContractJsonSerializerでJSONにシリアル化しているオブジェクトツリーを持っています。 Dictionary<TKey, TValue>はシリアル化されますが、私はマークアップを好きではない - の項目は次のようにレンダリングされません。DataContractJsonSerializerでJSONにDictionary <TKey、TValue>をシリアライズ

{key1:value, key2:value2} 

をではなく、シリアル化さKeyValuePair<TKey, TValue>オブジェクトの配列のように:

[{ 
    "__type":"KeyValuePairOfstringanyType:#System.Collections.Generic", 
    "key":"key1", 
    "value":"value1" 
},  
{ 
    "__type":"KeyValuePairOfstringanyType:#System.Collections.Generic", 
    "key":"key2", 
    "value":"value2" 
}] 

醜い、それはないです?

ISerializableを実装したカスタムオブジェクトに汎用ディクショナリをラップし、GetObjectDataメソッドでカスタムシリアル化を実装しています(それには3行しかかかりません)。

今問題 - 私は私のクラスは Dictionary<TKey, TValue>から派生することはできませんので、私はプライベート Dictionary<TKey, TValue>フィールドに適用されて、私のカスタムクラス内のすべてのロジック( AddClearなど)を実装しています。私のカスタムオブジェクトを使用しているときには、すべての汎用ディクショナリ機能を自由に使用できるため、継承が望ましいでしょう。

継承の問題は、Dictionary<TKey, TValue>が独自にISerializableを実装することで、DataContractJsonSerializerは、私は私のカスタムクラスから明示的ISerializableを実装した場合でも、このように、この実装を好むようだ:

public class MyClass : Dictionary<string, object>, ISerializable 
{ 
    public override void GetObjectData(SerializationInfo info, 
     StreamingContext context) 
} 

は、私が実際にその驚きましたこれは明示的なインターフェイス実装を明示的に使用することなく、同じインターフェイスを2回実装することができるので可能です。そのため、ブログの投稿で詳細を分析しました。about multiple interface implementation

したがって、

((ISerializable)obj).GetObjectData(...) 

が、それは明らかではありません。

((ISerializable)((Dictionary<,>)obj)).GetObjectData(...) 

かを - 私はそこに行った実験によれば、シリアライザは関係なく、内部的に使用される鋳物の種類、ISerializableの私の実装を呼び出してはなりません結果として生じるJSONで、シリアライザKeyValuePair<TKey, TValue>がまだ呼び出されているのがわかります。私が行方不明になっていることは何ですか?

更新: これまでの回答とコメントは、回避策を提案するだけです。結局、それはオリジナルのデザインで動作させる

  1. - と私は、シリアル化のロジックを変更するつもりはない。私は2つの目的を持って、私はこの質問を尋ねると非常によくその作品の回避策を持っていることに注意しましたそのためには、多くのコードとロジックが必要です。

  2. DataContractJsonSerializerは私のシリアライゼーションコードを使用していないのはなぜですか?私が言及したブログ記事に見られるように、インターフェイスの実装と継承に関するあらゆる種類の実験を行いました。私はプロセスのすべての面倒を把握していると確信していました。この問題で何が起こっているのか理解していないと困りますケース

+1

あなたがIEnumerableをクラスと辞書とあなたのISerializableのimplentationをラップすることができたようです。辞書から継承しようとするよりもはるかに少ない仕事。 –

+0

あなたが好きなように辞書をシリアライズするので、単に 'JavaScriptSerializer'を使うこともできます。 –

+0

@RitchMelton - 辞書を継承するのは大変な作業ではありませんが、IEnumerableを実装してメンバ辞書のgetEnumaratorを一目で返すことは、私の回避策よりも優れていることを認めなければなりません - – Vroomfundel

答えて

1

と思われます.DeviceContractJsonSerializerをカスタマイズするには、there is no wayとします。

希望するものを達成したい場合は、Json.Netの使用を検討してください。 DataContractJsonSerializerよりも高速で柔軟性があります。 Json.NetのJsonConverter構想を見てください。シリアライズ/デシリアライゼーションのプロセスをカスタマイズすることができます。

さらに、辞書のシリアル化のデフォルトの実装は、正確にhttp://james.newtonking.com/projects/json/help/SerializingCollections.htmlと同じです。

+1

答えをありがとう。 Dan Rigsbyのリンク記事では、DataContractSerializerは構成可能ではありませんが、明示的なGetObjectData実装が呼び出されない理由を調べてきた長さには至っていません。 それ以外は、json.netもよくわかります。プロジェクトのシリアライズエンジンを変更するだけで、影響が大きくなりすぎます。これは、私のカスタムディクショナリだけではありません。 – Vroomfundel

+0

Rigsbyリンクは現在死んでいます(DNS失敗)。これはすべて 'XmlObjectSerializer'に基づいているので、標準的なシリアライズのカスタマイズメカニズムはすべて利用可能です。残念ながら、これは「単純な」ものではありません(「代理プロパティ」の回答を参照してください)。 –

0

@Pashecが述べたように、あなたがJson.NETを使用している場合、あなたは次のことを試すことができます。

public Message <methodname> { 
    ... 
    string jsonMessage = JsonConvert.SerializeObject(myObjectTree); 
    return WebOperationContext.Current.CreateTextResponse(jsonMessage, "application/javascript; charset=utf-8", Encoding.UTF8); 
} 
4

1つのオプションは、代理​​プロパティを使用している辞書は、カ​​スタムISerializableの種類、そのようにあなたの内側にあるき継承について心配する必要はありません。

public Dictionary<string, string> NodeData { get; set; } 

[DataMember(Name="NodeData")] 
private CustomDictionarySerializer NodeDataSurrogate 
{ 
    get 
    { 
     return new CustomDictionarySerializer(NodeData); 
    } 
    set 
    { 
     NodeData = value._data; 
    } 
} 

[Serializable] 
private class CustomDictionarySerializer : ISerializable 
{ 
    public Dictionary<string, string> _data; 

    public CustomDictionarySerializer(Dictionary<string, string> dict) 
    { 
     _data = dict; 
    } 

    public CustomDictionarySerializer(SerializationInfo info, StreamingContext context) 
    { 
     _data = new Dictionary<string, string>(); 
     var valueEnum = info.GetEnumerator(); 
     while(valueEnum.MoveNext()) 
     { 
      _data[valueEnum.Current.Name] = valueEnum.Current.Value.ToString(); 
     } 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     foreach (var pair in _data) 
     { 
      info.AddValue(pair.Key, pair.Value); 
     } 
    } 
} 
+0

クラスを制御する場合、これは非常にうまく動作し、 'CustomDictionarySerializer' Value型をジェネリックパラメータにして、あらゆるタイプの辞書をシリアライズ(および逆シリアル化)できるようにします。参照型の値には、(デシリアライズの目的で) "__type"プロパティも追加されます。また、クラスで 'DataContract'属性を使用する必要があります。 –

関連する問題