无法反序列化Json数据

huangapple go评论74阅读模式
英文:

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&lt;Category[]&gt;(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&lt;int, Category&gt; Children { get; set; }
	public Category[] ChildrenArray { get; set; }

	public Category(JToken Children)
	{
		if(Children.Type == JTokenType.Object) this.Children=Children.ToObject&lt;Dictionary&lt;int, Category&gt;&gt;();
		else ChildrenArray = Children.ToObject&lt;Category[]&gt;();
	}
}

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&lt;Category&gt; Children { get; set; }

	[JsonConstructor]
	public Category(JToken Children)
	{
		if (Children.Type == JTokenType.Object)
		{
		    this.Children=new List&lt;Category&gt;();
			foreach (var prop in ((JObject)Children).Properties())
			{
				prop.Value[&quot;Id&quot;] = prop.Name;
				this.Children.Add(prop.Value.ToObject&lt;Category&gt;());
			}
		}
		else this.Children = Children.ToObject&lt;List&lt;Category&gt;&gt;();
	}
}

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&lt;Category&gt; Children { get; set; }
}

public class ChildrenConverter : JsonConverter&lt;List&lt;Category&gt;&gt;
{
	public override List&lt;Category&gt; ReadJson(JsonReader reader, Type objectType, List&lt;Category&gt; existingValue, bool hasExistingValue, JsonSerializer serializer)
	{
		var childrenObj = JToken.Load(reader);

		if (childrenObj.Type == JTokenType.Object)
		{
			var children = new List&lt;Category&gt;();
			foreach (var prop in ((JObject)childrenObj).Properties())
			{
				prop.Value[&quot;Id&quot;] = prop.Name;
				children.Add(prop.Value.ToObject&lt;Category&gt;());
			}
			return children;
		}
	    return childrenObj.ToObject&lt;List&lt;Category&gt;&gt;();
	}

	public override void WriteJson(JsonWriter writer, List&lt;Category&gt; 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&lt;string, JObject&gt; 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:

{
    &quot;&quot;categoryID&quot;&quot;: 117,
    &quot;&quot;name&quot;&quot;: &quot;&quot;jewellery&quot;&quot;,
    &quot;&quot;description&quot;&quot;: &quot;&quot;&quot;&quot;,
    &quot;&quot;parentCategoryID&quot;&quot;: null,
    &quot;&quot;countDiscussions&quot;&quot;: 243,
    &quot;&quot;countComments&quot;&quot;: 6716,
    &quot;&quot;children&quot;&quot;: {}
}

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

huangapple
  • 本文由 发表于 2023年7月24日 19:02:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76753824.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定