使用递归类型反序列化json [英] Deserializing json with recursive types

查看:79
本文介绍了使用递归类型反序列化json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些看起来像这样的json:

I've got some json that looks like this:

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

这可以用以下C#数据结构表示:

This can be represented with the following C# data structure:

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

我尝试将其反序列化为

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

,但是它不起作用,因为它不知道Items成员是该字典数据应该在递归调用中进行的位置.我该如何进行这项工作?

but it doesn't work because it doesn't know that the Items member is where this dictionary data is supposed to go on the recursive call. How can I make this work?

推荐答案

您的基本问题是您的JSON不代表MenuItem类列表的字典.相反,它表示MenuItem类字典的列表-数据模型中结构的相反.

Your basic problem is that your JSON does not represent a dictionary of lists of MenuItem classes. Instead, it represents a list of dictionaries of MenuItem classes - the reverse of the structure in your data model.

您可以通过几种方式表示和反序列化此内容:

You have several ways you could represent and deserialize this:

  1. MenuItem定义为MenuItem类型的词典列表的子类:

  1. Define your MenuItem as a subclass of a list of dictionaries of MenuItem types:

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

Json.NET可以立即反序列化此序列:

Json.NET will be able to deserialize this as-is out of the box:

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

  • 将您的MenuItem定义为包含MenuItem类型的字典列表:

  • Define your MenuItem as containing a list of dictionaries of MenuItem types:

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

    您将需要一个自定义转换器,将Items冒泡到JSON中的一个级别:

    You will need a custom converter to bubble the Items up one level in the 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);
    

  • 如果您确实希望数据模型成为列表的字典,而不是字典的列表,则在读取和编写数据模型时需要对其进行重组:

  • If you really want your data model to be a dictionary of lists rather than a list of dictionaries, you will need to restructure your data model as you read and write it:

    [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);
    

  • 原型显示所有三个的小提琴.

    这篇关于使用递归类型反序列化json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆