使用递归类型反序列化json [英] Deserializing json with recursive types
问题描述
我有一些看起来像这样的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:
-
将
MenuItem
定义为MenuItem
类型的词典列表的子类:
Define your
MenuItem
as a subclass of a list of dictionaries ofMenuItem
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屋!