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'屬性。 –

相關問題