我有一个对象树,我正在使用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>
,所以我在我的自定义类中实现了所有逻辑(Add
,Clear
等),正在应用到私人Dictionary<TKey, TValue>
字段。继承将是更可取的,因为在使用我的自定义对象时,我将拥有所有通用字典功能。
继承问题是Dictionary<TKey, TValue>
自己实现ISerializable
,DataContractJsonSerializer
似乎更喜欢这种实现,即使我从自定义类中明确实现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>
序列化程序仍然被调用。可能会发生什么,我失踪了?
更新: 到目前为止我得到的答案和评论几乎只是建议解决方法。然而,我注意到,我有一个非常有效的解决方法,所以在问这个问题时我有两个目标:
最终使其与原始设计一起工作 - 我不会仅仅为此更改序列化逻辑,有很多代码和逻辑依赖于它
为了解释为什么不是DataContractJsonSerializer
使用我的序列化代码的谜团 - 正如我在上面提到的博客文章中看到的那样,我已经通过接口实现和继承进行了各种实验。我相信我正在掌握这个过程的所有细节,所以我很难理解在这种情况下有什么好处
答案 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);
}