英文:
Unable to Deserialize Json data
问题
我可以帮你解决这个问题。问题出在 JSON 数据中的最后一个节点 (categoryID=117)。在你的代码中,Category
类中的 Children
属性被定义为 JObject
,但是最后一个节点的 children
字段是一个空数组,而不是一个对象。这导致了反序列化失败。
要解决这个问题,你可以将 Children
属性的类型更改为 JArray
,以便它可以容纳任何类型的子节点数据。这样,无论是对象还是数组,都可以正确地反序列化。
这是修改后的 Category
类:
public class Category
{
public string CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
public JArray Children { get; set; } // 将类型更改为 JArray
}
然后,你的代码应该可以成功反序列化整个 JSON 数据,包括最后一个节点。
英文:
I have a JSON data, which I want to Deserialize and load.
I'm able to Deserialize and load with partial data, but not with all.
Below is the code and the JSON data.
public class Category
{
public string CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
public JObject Children { get; set; }
}
public class ChildCategory
{
public int CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public int ParentCategoryID { get; set; }
public int CountDiscussions { get; set; }
public int CountComments { get; set; }
public JArray Children { get; set; }
}
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}");
Console.WriteLine($"Count of Discussions: {category.CountDiscussions}");
Console.WriteLine($"Count of Comments: {category.CountComments}");
Console.WriteLine("Children:");
foreach (var childCategory in category.Children)
{
var child = childCategory.Value.ToObject<ChildCategory>();
Console.WriteLine($" Category ID: {child.CategoryID}");
Console.WriteLine($" Name: {child.Name}");
Console.WriteLine($" Description: {child.Description}");
Console.WriteLine($" Parent Category ID: {child.ParentCategoryID}");
Console.WriteLine($" Count of Discussions: {child.CountDiscussions}");
Console.WriteLine($" Count of Comments: {child.CountComments}");
}
}
}
}
I'm able to load the data if I don't include the last node (categoryID=117, highlighted with **). But if I include it then my code is failing. Could anyone help me to fix this?
答案1
得分: 1
以下是翻译好的部分:
我认为一个类应该足够
var categories = JsonConvert.DeserializeObject<Category[]>(jsonData);
public class Category
{
public string CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
public Dictionary<int, Category> Children { get; set; }
public Category[] ChildrenArray { get; set; }
public Category(JToken Children)
{
if (Children.Type == JTokenType.Object) this.Children = Children.ToObject<Dictionary<int, Category>>();
else ChildrenArray = Children.ToObject<Category[]>();
}
}
或者如果你更喜欢使用 JObject 和 JArray,将其更改为 JToken:
public class Category
{
// ...其他属性
public JToken Children { get; set; }
}
但依我之见,更好的做法是将属性 Children 统一,将字典转换为数组:
public class Category
{
// ...其他属性
public int? Id { get; set; }
public List<Category> Children { get; set; }
[JsonConstructor]
public Category(JToken Children)
{
if (Children.Type == JTokenType.Object)
{
this.Children = new List<Category>();
foreach (var prop in ((JObject)Children).Properties())
{
prop.Value["Id"] = prop.Name;
this.Children.Add(prop.Value.ToObject<Category>());
}
}
else this.Children = Children.ToObject<List<Category>>();
}
}
或者,而不是使用 JSON 构造函数,你可以将此代码包装在一个 JSON 转换器中:
public class Category
{
// ...其他属性
public int? Id { get; set; }
[JsonConverter(typeof(ChildrenConverter))]
public List<Category> Children { get; set; }
}
public class ChildrenConverter : JsonConverter<List<Category>>
{
public override List<Category> ReadJson(JsonReader reader, Type objectType, List<Category> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var childrenObj = JToken.Load(reader);
if (childrenObj.Type == JTokenType.Object)
{
var children = new List<Category>();
foreach (var prop in ((JObject)childrenObj).Properties())
{
prop.Value["Id"] = prop.Name;
children.Add(prop.Value.ToObject<Category>());
}
return children;
}
return childrenObj.ToObject<List<Category>>();
}
public override void WriteJson(JsonWriter writer, List<Category> value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
英文:
I think that one class should be enough
var categories = JsonConvert.DeserializeObject<Category[]>(jsonData);
public class Category
{
public string CategoryID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
public Dictionary<int, Category> Children { get; set; }
public Category[] ChildrenArray { get; set; }
public Category(JToken Children)
{
if(Children.Type == JTokenType.Object) this.Children=Children.ToObject<Dictionary<int, Category>>();
else ChildrenArray = Children.ToObject<Category[]>();
}
}
or if you prefer JObject and JArray change it to JToken
public class Category
{
//...another properties
public JToken Children { get; set; }
}
but IMHO it is better to unify property Children by converting a dictionary to an array
public class Category
{
//...another properties
public int? Id { get; set; }
public List<Category> Children { get; set; }
[JsonConstructor]
public Category(JToken Children)
{
if (Children.Type == JTokenType.Object)
{
this.Children=new List<Category>();
foreach (var prop in ((JObject)Children).Properties())
{
prop.Value["Id"] = prop.Name;
this.Children.Add(prop.Value.ToObject<Category>());
}
}
else this.Children = Children.ToObject<List<Category>>();
}
}
or instead of a json constructor you can wrap this code in a json converter
public class Category
{
//...another properties
public int? Id { get; set; }
[JsonConverter(typeof(ChildrenConverter))]
public List<Category> Children { get; set; }
}
public class ChildrenConverter : JsonConverter<List<Category>>
{
public override List<Category> ReadJson(JsonReader reader, Type objectType, List<Category> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var childrenObj = JToken.Load(reader);
if (childrenObj.Type == JTokenType.Object)
{
var children = new List<Category>();
foreach (var prop in ((JObject)childrenObj).Properties())
{
prop.Value["Id"] = prop.Name;
children.Add(prop.Value.ToObject<Category>());
}
return children;
}
return childrenObj.ToObject<List<Category>>();
}
public override void WriteJson(JsonWriter writer, List<Category> value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
答案2
得分: -1
尽管更理想的做法是将一个类别类用于处理这种情况(如前面提到的),但如果您希望保持结构大致相同,以下是要解决的问题:
问题1:Category类需要读取对象字典:
public JObject Children { get; set; }
应更改为:
public Dictionary<string, JObject> Children { get; set; }
问题2:导致错误的Json部分中的Children条目应该是对象类型,而不是数组。您可以将空的children条目更改为使用{}而不是[]:
{
"categoryID": 117,
"name": "jewellery",
"description": "",
"parentCategoryID": null,
"countDiscussions": 243,
"countComments": 6716,
"children": {}
}
问题3:虽然它仍然可以运行,但为了更正确,您应该使用正确的数据类型来读取Json。Category类的以下属性:
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
应更改为整数,并且ParentCategoryID需要是可为空的,以允许Json中它为null的情况:
public int? ParentCategoryID { get; set; }
public int CountDiscussions { get; set; }
public int CountComments { get; set; }
在ChildCategory类中,我们有相同的问题,但我们不需要使ParentCategoryID可为空,因为那不可能发生。所以它们应该是:
public int ParentCategoryID { get; set; }
public int CountDiscussions { get; set; }
public int CountComments { get; set; }
英文:
Although moving to using one category class would be preferable (as mentioned in a previous post), in the event that you want to keep the structure roughly the same:
Problem 1: The Category class needs to read a dictionary of objects:
public JObject Children { get; set; }
This should be:
public Dictionary<string, JObject> Children { get; set; }
Problem 2: The Children entry on the part of the Json that causes the error should be an object type not an array. You could change it to use {} instead of [] for the empty children entry:
{
""categoryID"": 117,
""name"": ""jewellery"",
""description"": """",
""parentCategoryID"": null,
""countDiscussions"": 243,
""countComments"": 6716,
""children"": {}
}
Problem 3: Though it will still run, to be more correct you should use the correct data types for reading the Json. The following properties of the Category class:
public string ParentCategoryID { get; set; }
public string CountDiscussions { get; set; }
public string CountComments { get; set; }
These should all be integers and the ParentCategoryID needs to be nullable in order to allow the case where it is null in the Json:
public int? ParentCategoryID { get; set; }
public int CountDiscussions { get; set; }
public int CountComments { get; set; }
In the ChildCategory class we have the same problem but we don't need the ParentCategoryID to be nullable as that can't happen. So they should be:
public int ParentCategoryID { get; set; }
public int CountDiscussions { get; set; }
public int CountComments { get; set; }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论