JSON反序列化失败:含categoryID=117节点时代码报错求助
问题修复方案
错误原因分析
- Children类型不兼容:JSON中大部分父节点的
children是键值对形式的对象(如{"57": {...}}),但categoryID=117的children是空数组[],而原代码中Category类将Children定义为JObject,数组无法直接反序列化为JObject,这是导致执行失败的直接原因。 - 数据类型不匹配:
Category类中CategoryID、ParentCategoryID等字段定义为string,但JSON中对应值是数字或null,虽Json.NET有隐式转换,但容易引发类型异常。 - 类结构冗余:
ChildCategory和Category结构高度重复,没必要单独定义,用递归结构更合理。
修复步骤
1. 统一处理Children的类型差异
自定义JsonConverter,识别children字段的类型(数组或对象),将空数组转换为空字典,保证类型兼容。
2. 修正数据类型匹配
将Category类中数字类型字段改为int或int?(支持null),匹配JSON中的数据类型。
3. 简化类结构
删除ChildCategory类,用Dictionary<string, Category>存储子节点,通过递归结构处理嵌套层级。
完整修复代码
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; public class Category { [JsonProperty("categoryID")] public int CategoryID { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("description")] public string Description { get; set; } [JsonProperty("parentCategoryID")] public int? ParentCategoryID { get; set; } [JsonProperty("countDiscussions")] public int CountDiscussions { get; set; } [JsonProperty("countComments")] public int CountComments { get; set; } [JsonProperty("children")] [JsonConverter(typeof(ChildrenConverter))] public Dictionary<string, Category> Children { get; set; } = new Dictionary<string, Category>(); } public class ChildrenConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Dictionary<string, Category>); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); if (token.Type == JTokenType.Array) { // 空数组转换为空字典 return new Dictionary<string, Category>(); } else if (token.Type == JTokenType.Object) { // 对象直接反序列化为字典 return token.ToObject<Dictionary<string, Category>>(serializer); } return null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } public class Program { public static void Main() { string jsonData = @"[ { ""categoryID"": 93, ""name"": ""Cloths"", ""description"": """", ""parentCategoryID"": null, ""countDiscussions"": 10, ""countComments"": 20, ""children"": { ""57"": { ""categoryID"": 180, ""name"": ""Shirt"", ""description"": """", ""parentCategoryID"": 9, ""countDiscussions"": 2, ""countComments"": 4, ""children"": [] }, ""56"": { ""categoryID"": 187, ""name"": ""ShirtAAAAA"", ""description"": """", ""parentCategoryID"": 9, ""countDiscussions"": 2, ""countComments"": 4, ""children"": [] } } }, { ""categoryID"": 172, ""name"": ""accessories"", ""description"": """", ""parentCategoryID"": null, ""countDiscussions"": 15, ""countComments"": 47, ""children"": { ""2"": { ""categoryID"": 191, ""name"": ""Watch"", ""description"": """", ""parentCategoryID"": 172, ""countDiscussions"": 1, ""countComments"": 0, ""children"": [] } } }, { ""categoryID"": 117, ""name"": ""jewellery"", ""description"": """", ""parentCategoryID"": null, ""countDiscussions"": 243, ""countComments"": 6716, ""children"": [] } ]"; var categories = JsonConvert.DeserializeObject<Category[]>(jsonData); foreach (var category in categories) { Console.WriteLine($"Category ID: {category.CategoryID}"); Console.WriteLine($"Name: {category.Name}"); Console.WriteLine($"Description: {category.Description}"); Console.WriteLine($"Parent Category ID: {category.ParentCategoryID ?? 0}"); Console.WriteLine($"Count of Discussions: {category.CountDiscussions}"); Console.WriteLine($"Count of Comments: {category.CountComments}"); Console.WriteLine("Children:"); foreach (var childEntry in category.Children) { var child = childEntry.Value; Console.WriteLine($" Key: {childEntry.Key}"); Console.WriteLine($" Category ID: {child.CategoryID}"); Console.WriteLine($" Name: {child.Name}"); Console.WriteLine($" Description: {child.Description}"); Console.WriteLine($" Parent Category ID: {child.ParentCategoryID ?? 0}"); Console.WriteLine($" Count of Discussions: {child.CountDiscussions}"); Console.WriteLine($" Count of Comments: {child.CountComments}"); } Console.WriteLine("------------------------"); } } }
修复说明
- 自定义转换器:
ChildrenConverter自动处理children字段的类型差异,空数组转为空字典,避免转换异常。 - 类型匹配:将数字类字段改为
int/int?,完美适配JSON中的数字和null值,消除类型转换风险。 - 递归结构:用
Dictionary<string, Category>存储子节点,既符合JSON的键值对结构,又支持无限层级的嵌套子节点解析。 - null值处理:输出时用
?? 0将null替换为0,也可根据需求改为显示"null"。
内容的提问来源于stack exchange,提问作者Sreepu
相关产品推荐
相关产品推荐

