2016-01-23 84 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