使用DataContractJsonSerializer将字典<tkey,tvalue =“”>序列化为JSON,</tkey,>

时间:2011-09-21 10:23:38

标签: .net oop serialization datacontractjsonserializer multiple-interface-implem

我有一个对象树,我正在使用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"
 }]

丑陋,不是吗?

因此,我通过将通用Dictionary包装在实现ISerializable的自定义对象中来避免这种情况,并且我在GetObjectData方法中实现了自定义序列化(它只需要3行)。

现在问题了 - 我无法让我的课程来自Dictionary<TKey, TValue>,所以我在我的自定义类中实现了所有逻辑(AddClear等),正在应用到私人Dictionary<TKey, TValue>字段。继承将是更可取的,因为在使用我的自定义对象时,我将拥有所有通用字典功能。

继承问题是Dictionary<TKey, TValue>自己实现ISerializableDataContractJsonSerializer似乎更喜欢这种实现,即使我从自定义类中明确实现ISerializable,像这样:

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

我真的很惊讶这是可能的,因为它允许我实现相同的接口两次而不显然能够使用显式接口实现 - 所以我在博客文章about multiple interface implementation中更详细地分析了这种情况

所以,根据我在那里做的实验,序列化器应该调用我的ISerializable实现,无论内部使用什么类型的转换 -

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

或:

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

但显然没有发生,因为我在生成的JSON中看到KeyValuePair<TKey, TValue>序列化程序仍然被调用。可能会发生什么,我失踪了?

更新: 到目前为止我得到的答案和评论几乎只是建议解决方法。然而,我注意到,我有一个非常有效的解决方法,所以在问这个问题时我有两个目标:

  1. 最终使其与原始设计一起工作 - 我不会仅仅为此更改序列化逻辑,有很多代码和逻辑依赖于它

  2. 为了解释为什么不是DataContractJsonSerializer使用我的序列化代码的谜团 - 正如我在上面提到的博客文章中看到的那样,我已经通过接口实现和继承进行了各种实验。我相信我正在掌握这个过程的所有细节,所以我很难理解在这种情况下有什么好处

3 个答案:

答案 0 :(得分:4)

一个选项是使用代理属性并将字典放在自定义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);
        }
    }
}

答案 1 :(得分:1)

似乎,there is no way来自定义DataContractJsonSerializer。

如果您仍想达到自己想要的效果,请考虑使用Json.Net。它比DataContractJsonSerializer更快,更灵活。看看JsonConverter对Json.Net的概念。它使您可以自定义序列化/反序列化过程。

此外,字典序列化的默认实现完全符合您的要求http://james.newtonking.com/projects/json/help/SerializingCollections.html

答案 2 :(得分:0)

正如@Pashec所提到的,如果你使用Json.NET,你可以尝试以下方法:

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