2011-06-20 43 views
7

顯然,IDictionary<string,object>被序列化爲KeyValuePair對象的數組(例如,[{Key:"foo", Value:"bar"}, ...])。是否可以將其序列化爲對象(例如,{foo:"bar"})?使用JavaScriptSerializer序列化字典

+3

是,不使用JavaScriptSerializer,它完全扯淡。使用Newtonsoft Json.NET –

回答

10

雖然我同意JavaScriptSerializer是廢話,Json.Net是一個更好的選擇,您可以使JavaScriptSerializer以您想要的方式序列化。 你將不得不註冊一個轉換器,並使用這樣的重寫Serialize方法:

public class KeyValuePairJsonConverter : JavaScriptConverter 
{ 
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) 
    { 
     var instance = Activator.CreateInstance(type); 

     foreach (var p in instance.GetType().GetPublicProperties()) 
     { 
      instance.GetType().GetProperty(p.Name).SetValue(instance, dictionary[p.Name], null); 
      dictionary.Remove(p.Name); 
     } 

     foreach (var item in dictionary) 
      (instance).Add(item.Key, item.Value); 

     return instance; 
    } 
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) 
    { 
     var result = new Dictionary<string, object>(); 
     var dictionary = obj as IDictionary<string, object>; 
     foreach (var item in dictionary) 
      result.Add(item.Key, item.Value); 
     return result; 
    } 
    public override IEnumerable<Type> SupportedTypes 
    { 
     get 
     { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(your_type) }); 
     } 
    } 
} 

JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer(); 
javaScriptSerializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJsonConverter() }); 
jsonOfTest = javaScriptSerializer.Serialize(test); 
// {"x":"xvalue","y":"\/Date(1314108923000)\/"} 

希望這有助於!

+0

我想使用你的類,但它似乎你的'類對象'''實例'變量沒有添加方法。 –

4

不,這不可能與JavaScriptSerializer。這是可能的Json.NET

public class Bar 
{ 
    public Bar() 
    { 
     Foos = new Dictionary<string, string> 
     { 
      { "foo", "bar" } 
     }; 
    } 

    public Dictionary<string, string> Foos { get; set; } 
} 

然後:

var bar = new Bar(); 
string json = JsonConvert.SerializeObject(bar, new KeyValuePairConverter()); 

產生所需:

{"Foos":{"foo":"bar"}} 
+0

我一開始就要走這條路。看到我以前的問題:http://stackoverflow.com/questions/6416017/json-net-deserializing-nested-dictionaries。我有一個使用Json.NET反序列化嵌套字典的問題。 – Daniel

+2

@Daniel,Json.NET與'JavaScriptSerializer'相比是糖。所以,如果你在使用Json.NET時遇到問題,我不知道該怎麼說另一種方法:-)就你的其他問題而言,這是完全正常的行爲。您向串行器指出的所有內容都是字符串和對象的字典。所以你在代碼中使用弱類型的字典,你期待什麼?所有你當然可以得到的是一個弱類型的JObjects。使用一個強類型的字典:'Dictionary ',會有區別。 –

+0

你指的是什麼區別?我沒有看到它。 – Daniel

1

我能夠使用JavaScriptSerializer解決它,訣竅是創建自己的轉換器。下面的代碼工作代碼:

public class KeyValuePairJsonConverter : JavaScriptConverter { 
    public override object Deserialize(IDictionary<string, object> dictionary 
             , Type type 
             , JavaScriptSerializer serializer) { 
     throw new InvalidOperationException("Sorry, I do serializations only."); 
    } 

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     Dictionary<string, MyClass> dictionaryInput = obj as Dictionary<string, MyClass>; 

     if (dictionaryInput == null) { 
      throw new InvalidOperationException("Object must be of Dictionary<string, MyClass> type."); 
     } 

     foreach (KeyValuePair<string, MyClass> pair in dictionaryInput) 
      result.Add(pair.Key, pair.Value); 

     return result; 
    } 

    public override IEnumerable<Type> SupportedTypes { 
     get { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(Dictionary<string, MyClass>) }); 
     } 
    } 
} 

這裏是你如何使用它:

JavaScriptSerializer js = new JavaScriptSerializer(); 
js.RegisterConverters(new JavaScriptConverter[] { new KeyValuePairJsonConverter() }); 
Context.Response.Clear(); 
Context.Response.ContentType = "application/json"; 
Context.Response.Write(js.Serialize(myObject)); 
1

這裏有一個我相信從托馬斯的回答改進版本。奇蹟般有效。我們也可以爲ScriptIgnore屬性添加一個檢查,但是也可以自己敲一下。

順便說一下,我選擇了JavaScriptSerializer,因爲在我看來,第三方解決方案大部分時間都是這樣:不太知道,安裝時間長,經常被遺忘的先決條件和模糊的版權狀態,這使得它們在商業中分發風險更大。

P-S:我沒有理解爲什麼我們試圖將實例和實例反序列化爲字典,所以我剝去了這部分。

public class KeyValuePairJsonConverter : JavaScriptConverter 
{ 
    public override object Deserialize(IDictionary<string, object> deserializedJSObjectDictionary, Type targetType, JavaScriptSerializer javaScriptSerializer) 
    { 
     Object targetTypeInstance = Activator.CreateInstance(targetType); 

     FieldInfo[] targetTypeFields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance); 

     foreach (FieldInfo fieldInfo in targetTypeFields) 
      fieldInfo.SetValue(targetTypeInstance, deserializedJSObjectDictionary[fieldInfo.Name]); 

     return targetTypeInstance; 
    } 

    public override IDictionary<string, object> Serialize(Object objectToSerialize, JavaScriptSerializer javaScriptSerializer) 
    { 
     IDictionary<string, object> serializedObjectDictionary = new Dictionary<string, object>(); 

     FieldInfo[] objectToSerializeTypeFields = objectToSerialize.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); 

     foreach (FieldInfo fieldInfo in objectToSerializeTypeFields) 
      serializedObjectDictionary.Add(fieldInfo.Name, fieldInfo.GetValue(objectToSerialize)); 

     return serializedObjectDictionary; 
    } 

    public override IEnumerable<Type> SupportedTypes 
    { 
     get 
     { 
      return new ReadOnlyCollection<Type>(new Type[] { typeof(YOURCLASSNAME) }); 
     } 
    } 
} 
+0

關於我的PS筆記。也許這是爲了允許specidying通用字典類型,而不是類型,但老實說,我沒有看到指定通用字典類型的要點,因爲這整個事情是關於反序列化字典。而且它是cubersome。 – Olograph

2

我能夠解決JavaScriptSerializer LINQ的選擇:

var dictionary = new Dictionary<int, string>(); 
var jsonOutput = new JavaScriptSerializer().Serialize(dictionary.Select(x => new { Id = x.Key, DisplayText = x.Value })); 
+0

這在複雜情況下(即複雜的層次結構)不起作用,但它確實解決了這個問題,因此如果您想避免向JavaScriptSerializer或第三方庫添加樣板文件,這是一個解決方案。 –

+0

對於我來說,即使在複雜的情況下,它也可以工作,只需更改爲'.Serialize(dictionary)'。它更簡單,然後JsonConvert,準備使用。我希望我能給+2這個答案 –

相關問題