如何用Newtonsoft.Json反序列化可变数组键的JSON到泛型类?
实现方案:动态捕获JSON数组属性名并映射到字典
当然可以实现这个需求,核心思路是不硬编码数组属性名,而是在反序列化过程中动态识别JSON中的数组类型属性,将属性名作为字典键、数组内容转为List<Friend>作为值存入目标属性。下面是两种实用的实现方式:
方案一:自定义Json转换器(推荐,通用可复用)
通过编写自定义JsonConverter,可以让Newtonsoft.Json在反序列化时自动处理动态属性名的映射,无需每次手动解析,适合批量处理20个JSON文件的场景。
1. 定义实体类
保留原有Person类的基础属性,将原List<Friend>替换为Dictionary<string, List<Friend>>:
public class Person { // 原有的基础属性(示例) public string Name { get; set; } public int Age { get; set; } // 存储动态捕获的数组分组 public Dictionary<string, List<Friend>> ContactGroups { get; set; } = new(); } public class Friend { public string FriendName { get; set; } public string Phone { get; set; } }
2. 编写自定义转换器
继承JsonConverter<Person>,在ReadJson方法中解析JSON对象,提取所有数组类型的属性:
public class PersonDynamicGroupsConverter : JsonConverter<Person> { public override Person ReadJson(JsonReader reader, Type objectType, Person existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); var person = existingValue ?? new Person(); // 先反序列化基础属性(Name、Age等) serializer.Populate(jsonObj.CreateReader(), person); // 遍历所有JSON属性,筛选出数组类型的项 foreach (var prop in jsonObj.Properties()) { if (prop.Value.Type == JTokenType.Array) { // 将数组转为List<Friend>,存入字典 var friendList = prop.Value.ToObject<List<Friend>>(serializer); person.ContactGroups[prop.Name] = friendList; } } return person; } public override void WriteJson(JsonWriter writer, Person value, JsonSerializer serializer) { // 如果需要将Person序列化回JSON,可在这里实现反向逻辑 var jsonObj = JObject.FromObject(value, serializer); foreach (var group in value.ContactGroups) { jsonObj.Add(group.Key, JArray.FromObject(group.Value, serializer)); } jsonObj.WriteTo(writer); } }
3. 使用转换器反序列化
反序列化时指定自定义转换器即可:
// 读取任意一个JSON文件 var jsonContent = File.ReadAllText("sample.json"); var person = JsonConvert.DeserializeObject<Person>(jsonContent, new PersonDynamicGroupsConverter()); // 遍历字典查看捕获的属性名和对应好友列表 foreach (var group in person.ContactGroups) { Console.WriteLine($"分组属性名:{group.Key}"); foreach (var friend in group.Value) { Console.WriteLine($" 好友:{friend.FriendName}"); } }
方案二:手动解析JObject(快速实现,灵活可控)
如果不需要复用转换器,也可以直接将JSON解析为JObject,手动提取数组属性并映射到Person类:
var jsonContent = File.ReadAllText("sample.json"); var jsonObj = JObject.Parse(jsonContent); var person = new Person { Name = jsonObj["Name"]?.ToString(), Age = jsonObj["Age"]?.ToObject<int>() ?? 0, ContactGroups = new() }; // 遍历所有属性,筛选数组类型 foreach (var prop in jsonObj.Properties()) { if (prop.Value.Type == JTokenType.Array) { person.ContactGroups[prop.Name] = prop.Value.ToObject<List<Friend>>(); } }
方案对比
- 自定义转换器:一次编写,多次复用,代码结构更清晰,适合批量处理多个JSON文件的场景。
- 手动解析JObject:代码更简洁,无需额外编写转换器,适合临时或简单场景。
两种方案都能完美满足你的需求:动态捕获所有不同的数组属性名(如friends、mates、companions),并将对应数组内容存入字典中。
内容的提问来源于stack exchange,提问作者Happy Coconut
相关产品推荐
相关产品推荐

