json.net - 使用递归类型反序列化 json

标签 json.net

我有一些如下所示的 json:

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

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

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

我尝试将其反序列化为

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

但它不起作用,因为它不知道 Items 成员是该字典数据应该进行递归调用的位置。我怎样才能做到这一点?

最佳答案

您的基本问题是您的 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;
    }
    

    您将需要一个自定义转换器来将 JSON 中的 Items 向上冒泡:

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

原型(prototype) fiddle showing all three .

关于json.net - 使用递归类型反序列化 json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34960853/

相关文章:

c# - 使用 JSON.NET 反序列化值为字段名称的 JSON

c# - 无法将 json 解析为自定义对象列表

c# - 使用 JSON.NET 反序列化 Noda Time 的 LocalDateTime

c# - 无法使用 NewtonSoft JSONConvert 解析 JSON

c# - 使用 Newtonsoft 的 JSON C# 问题

javascript - 如何将枚举数组序列化为 Json 字符串数组?

c# - 使用 HTTPClient PostAsync 发送数组

c# - 在 C# 中将查询字符串序列化为 Json - 值不显示,仅显示键。为什么?

c# - 将Json String反序列化为多种Object类型

c# - JSON.NET ANY ContractResolver 导致性能不佳