2016-01-23 101 views
2

我有一些JSON,看起來像這樣:反序列化JSON遞歸類型

[ 
    { 
    "MenuItem1": [ 
     { "SubItem1": [ ] }, 
     { "SubItem2": [ ] }, 
     { "SubItem3": [ 
      { "SubSubItem": [ ] } 
     ] 
     } 
    ] 
    }, 
    { "MenuItem2": [ ] } 
] 

這可以用下面的C#的數據結構來表示:

class MenuItem 
{ 
    Dictionary<string, MenuItem[]> Items; 
} 

我試圖反序列化這是

MenuItem[] roots = JsonConvert.DeserializeObject<MenuItem[]>(json); 

但它不起作用,因爲它不知道Items成員是幹什麼的這個字典數據應該是遞歸調用。我該如何做這項工作?

+0

[看看這個網站。](http://json2csharp.com/) –

+0

沒有幫助,嵌套可以任意深度和深度是可變的,所以固定深度的方法將無法工作 –

回答

2

你的基本問題是,你的JSON並不代表MenuItem類的列表的字典。相反,它代表MenuItem類的詞典列表 - 在您的數據模型結構相反。

您有幾種方法,你可以代表和反序列化這樣的:

  1. 定義你的MenuItem作爲MenuItem類型的字典列表的一個子類:

    public class MenuItem : List<Dictionary<string, MenuItem>> 
    { 
    } 
    

    Json.NET就能按原樣開箱即可反序列化:

    var root = JsonConvert.DeserializeObject<MenuItem>(json); 
    
  2. 定義你的MenuItem含有MenuItem類型的字典列表:

    [JsonConverter(typeof(MenuItemConverter))] 
    class MenuItem 
    { 
        public Dictionary<string, MenuItem> [] Items; 
    } 
    

    您將需要一個自定義的轉換到泡沫Items了在JSON一層:

    public class MenuItemConverter : JsonConverter 
    { 
        public override bool CanConvert(Type objectType) 
        { 
         return objectType == typeof(MenuItem); 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         var items = serializer.Deserialize<Dictionary<string, MenuItem>[]>(reader); 
         return new MenuItem { Items = items }; 
        } 
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         var item = (MenuItem)value; 
         serializer.Serialize(writer, item.Items); 
        } 
    } 
    

    和反序列化,再次:

    var root = JsonConvert.DeserializeObject<MenuItem>(json); 
    
  3. 如果你真的想你的數據模型是一個列表而不是字典列表的字典,你將需要爲你讀重組你的數據模型,並寫:

    [JsonConverter(typeof(MenuItemConverter))] 
    class MenuItem 
    { 
        public MenuItem() { this.Items = new Dictionary<string, List<MenuItem>>(); } 
        public Dictionary<string, List<MenuItem>> Items; 
    } 
    
    public static class DictionaryExtensions 
    { 
        public static void Add<TKey, TValueList, TValue>(this IDictionary<TKey, TValueList> listDictionary, TKey key, TValue value) 
         where TValueList : IList<TValue>, new() 
        { 
         if (listDictionary == null) 
          throw new ArgumentNullException(); 
         TValueList values; 
         if (!listDictionary.TryGetValue(key, out values)) 
          listDictionary[key] = values = new TValueList(); 
         values.Add(value); 
        } 
    
        public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(TKey key, TValue value) 
        { 
         var dict = new Dictionary<TKey, TValue>(); 
         dict[key] = value; 
         return dict; 
        } 
    } 
    
    public class MenuItemConverter : JsonConverter 
    { 
        public override bool CanConvert(Type objectType) 
        { 
         return objectType == typeof(MenuItem); 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         var items = serializer.Deserialize<Dictionary<string, MenuItem>[]>(reader); 
         var menuItem = new MenuItem(); 
         foreach (var pair in items.SelectMany(d => d)) 
          menuItem.Items.Add(pair.Key, pair.Value); 
         return menuItem; 
        } 
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         var menuItem = (MenuItem)value; 
         if (menuItem.Items == null) 
          writer.WriteNull(); 
         else 
         { 
          var list = menuItem.Items.SelectMany(p => p.Value.Select(m => DictionaryExtensions.ToDictionary(p.Key, m))); 
          serializer.Serialize(writer, list); 
         } 
        } 
    } 
    

    然後

    var root = JsonConvert.DeserializeObject<MenuItem>(json); 
    

原型fiddle showing all three