15

我有一个对象树,我序列化为JSON与DataContractJsonSerializerDictionary<TKey, TValue>被序列化,但我不喜欢的标记 - 该项目不呈现:序列化字典<TKey,TValue>与JSON与DataContractJsonSerializer

{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>派生,所以我实现所有的逻辑(AddClear等),在我的自定义类,被应用到私人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>串行器仍然被调用。我错过了什么?

更新: 我所得到的答案和评论几乎只提供了解决方法。然而,我注意到,我有跟提出这个问题,工作得非常好这样一个解决办法我有两个目标:

  1. 最终使其与原创设计作品 - 我不会改变序列化逻辑为此,有很多代码和逻辑依赖于它

  2. 为了不使用我的序列化代码为什么不是DataContractJsonSerializer的谜团 - 我可以在我提到的博客文章中看到,我已经提出各种各样的接口实现和继承实验,我确信我掌握了这个过程的所有细节,所以我很难理解这个过程中发生了什么。 case

+1

看起来你可以用IEnumerable类和你的ISerializable实现包装字典。比尝试从字典继承更少的工作。 –

+0

您也可以使用'JavaScriptSerializer',因为它会按照您的喜好序列化字典。 –

+0

@RitchMelton - 从字典继承并不是很多工作,但我必须承认,实现IEnumerable并一看就返回成员字典的getEnumarator似乎比我的解决方法更好 - 只有一种方法实现 – Vroomfundel

回答

1

似乎,there is no way来定制DataContractJsonSerializer。

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

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

+1

感谢您的答案。 Dan Rigsby的链接文章中提到DataContractSerializer是不可配置的,但它不会在我探索为什么显式的GetObjectData实现没有被调用的时候走近任何距离。 除此之外,我很了解json.net,我知道这很好 - 只是改变项目中的序列化引擎会产生太大的影响 - 这不仅仅是我的自定义Dictionary正在序列化 – 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

一种选择是使用替代性和有字典是定制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'属性。 –

相关问题