15

を使用して JSON にシリアル化するオブジェクト ツリーがありますDataContractJsonSerializerDictionary<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"
 }]

醜いですね。

そのため、汎用 Dictionary を を実装するカスタム オブジェクトにラップすることでこれを回避しISerializable、カスタム シリアル化をGetObjectDataメソッドに実装します (わずか 3 行で済みます)。

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

継承の問題は、独自にDictionary<TKey, TValue>実装することであり、次のようにカスタム クラスから明示的に実装したとしても、この実装を好むようです。ISerializableDataContractJsonSerializerISerializable

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

明らかに明示的なインターフェイス実装を使用できなくても、同じインターフェイスを 2 回実装できるため、これが可能であることに実際に驚きました。そのため、複数のインターフェイスの実装に関するブログ投稿で状況をより詳細に分析しました。

したがって、そこで行った実験によると、内部で使用されているキャストのタイプに関係なく、シリアライザーは ISerializable の実装を呼び出す必要があります-

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

また:

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

KeyValuePair<TKey, TValue>しかし、シリアライザーがまだ呼び出されている結果のJSONでわかるように、それは明らかに起こっていません。私が行方不明になっていると何が起こっているのでしょうか?

更新: これまでに得た回答とコメントは、回避策を示唆しているだけです。ただし、非常にうまく機能する回避策があることに注意してください。この質問をすることで、2つの目的があります。

  1. 最終的には元の設計で動作するようにします。そのためだけにシリアライゼーション ロジックを変更するつもりはありません。多くのコードとロジックが依存しています。

  2. なぜシリアライゼーション コードを使用しないのかという謎を解明するために、DataContractJsonSerializer参照したブログ投稿に見られるように、インターフェイスの実装と継承についてあらゆる種類の実験を行い、すべての実装を把握していると確信していました。プロセスから外れたので、この場合何が起こっているのか理解できずに困っています

4

3 に答える 3

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);
        }
    }
}
于 2013-09-17T21:32:57.490 に答える
1

DataContractJsonSerializerをカスタマイズする方法はないようです。

それでも目的を達成したい場合は、Json.Netの使用を検討してください。DataContractJsonSerializer よりも高速で柔軟です。Json.Net の JsonConverter の概念を見てください。シリアライゼーション/デシリアライゼーション プロセスをカスタマイズする可能性を提供します。

さらに、ディクショナリのシリアル化のデフォルトの実装は、http://james.newtonking.com/projects/json/help/SerializingCollections.htmlのように正確です。

于 2011-10-10T13:37:20.353 に答える
0

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

public Message <methodname> {
    ...
    string jsonMessage = JsonConvert.SerializeObject(myObjectTree);
    return WebOperationContext.Current.CreateTextResponse(jsonMessage, "application/javascript; charset=utf-8", Encoding.UTF8);
}
于 2012-02-24T21:14:47.713 に答える