15

我有一个对象树,我用DataContractJsonSerializer. 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 功能。

继承的问题在于它自己Dictionary<TKey, TValue>实现ISerializable,并且DataContractJsonSerializer似乎更喜欢这种实现,即使我ISerializable从我的自定义类中显式实现,如下所示:

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

实际上,我很惊讶这是可能的,因为它允许我两次实现相同的接口,而显然无法使用显式接口实现 - 所以我在一篇关于多接口实现的博客文章中更详细地分析了这种情况

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

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

或者:

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

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

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

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

  2. 为了解开为什么不DataContractJsonSerializer使用我的序列化代码的奥秘 - 正如我提到的博客文章中所见,我已经对接口实现和继承进行了各种实验,并且我确信我掌握了所有内容和过程之外,所以我对无法理解在这种情况下发生的事情感到困扰

4

3 回答 3

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);
        }
    }
}
于 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 回答