【问题标题】:Unable to Deserialize data from Nested JSON List无法反序列化嵌套 JSON 列表中的数据
【发布时间】:2020-12-14 07:26:31
【问题描述】:

在了解了 C# 类 Constructors 和 ArrayLists 之后来到这里,以免在这里提出一个完全愚蠢的问题 :)

我正在尝试反序列化以下从 API GET 调用返回的 JSON 嵌套列表:

我已经能够从empArra(字段:Emp)中获取值,但随后的列表(如yearArrayprodsale)没有返回那里的值。

你能看看下面的代码哪里做错了吗?

JSON

 [
    {
        "employee":"156718100",
        "availability":[
            {
                "year":2018,
                "sales":{
                    "availability":"Maybe",
                    "reason":""
                },
                "prod":{
                    "availability":"Maybe",
                    "reason":""
                }
            },
            {
                "year":2019,
                "sales":{
                    "availability":"Maybe",
                    "reason":""
                },
                "prod":{
                    "availability":"Maybe",
                    "reason":""
                }
            },
            {
                "year":2020,
                "sales":{
                    "availability":"Maybe",
                    "reason":""
                },
                "top":{
                    "availability":"Maybe",
                    "reason":""
                }
            },
            {
                "year":2021,
                "sales":{
                    "availability":"Maybe",
                    "reason":""
                },
                "prod":{
                    "availability":"Maybe",
                    "reason":""
                }
            }
        ]
    }
]

public class sale
{
    public string SaleAvailability { get; set; }
    public string SaleReason { get; set; }
    
    public sale(string pSaleAvailability, string pSaleReason)
    {
        this.SaleAvailability = pSaleAvailability;
        this.SaleReason = pSaleReason;
    }
    
    public override string ToString()
    {
        return string.Format("{0} {1}", SaleAvailability, SaleReason);
    }
}

public class prod
{
    public string ProdAvailability { get; set; }
    public string ProdReason { get; set; }
    
    public prod(string pProdAvailability, string pProdReason)
    {
        this.ProdAvailability = pProdAvailability;
        this.ProdReason = pProdReason;
    }
    
    public override string ToString()
    {
        return string.Format("{0} {1}", ProdAvailability, ProdReason);
    }
}

public class yearArray
{
    public int Year { get; set; }

    public yearArray(int pYear)
    {
        this.Year = pYear;
    }

    List<sale> Sale { get; set; } = new List<sale>();
    List<prod> Prod { get; set; } = new List<prod>();
}

public class rootAvailability
{
    public List<yearArray> YearArray { get; set; } = new List<yearArray>();
}

public class empArray
{
    public string Emp { get; set; }
    public List<rootAvailability> RootAvailability { get; set; } = new List<rootAvailability>();
}

public class rootArray
{
    public List<empArray> EmpArrays { get; set; } = new List<empArray>();

}

main()方法

(从 API 获取响应后)

IRestResponse response = client.Execute<rootArray>(request);
    
//Console.WriteLine(response.Content);

List<rootArray> rootArrays = JsonConvert.DeserializeObject<List<rootArray>>(response.Content);

List<empArray> empArrays = JsonConvert.DeserializeObject<List<empArray>>(response.Content);

List<rootAvailability> rootAvailabilities = JsonConvert.DeserializeObject<List<rootAvailability>>(response.Content);

List<yearArray> yearArrays = JsonConvert.DeserializeObject<List<yearArray>>(response.Content);

List<sale> clsSale = JsonConvert.DeserializeObject<List<sale>>(response.Content);

List<prod> clsProd = JsonConvert.DeserializeObject<List<prod>>(response.Content);


foreach (var rootitem in rootArrays)
{
    foreach (var emparrayitem in empArrays)
    {
        Console.WriteLine("NSN: " + emparrayitem.Emp);
        
        foreach (var rootavailabbilitiesitem in rootAvailabilities)
        {
            
            foreach (var yearArrayItem in yearArrays)
            {
                
                Console.WriteLine("Year: " + yearArrayItem.Year);

                foreach (var saleItem in clsSale)
                {

                    Console.WriteLine("SaleAvailability: " + saleItem.SaleAvailability);
                    Console.WriteLine("SaleReason: " + saleItem.SaleReason);
                }
                foreach (var prodItem in clsProd)
                {

                    Console.WriteLine("SaleAvailability: " + prodItem.ProdAvailability);
                    Console.WriteLine("SaleReason: " + prodItem.ProdReason);
                }
            }
        }
    }
}

结果

Emp: 159252663
Year: 0
SaleAvailability:
SaleReason:
SaleAvailability:
SaleReason:

【问题讨论】:

  • 我看到的一个明显问题是您一次又一次地反序列化内容。作为包含所有嵌套列表和对象的类,您应该只反序列化一次。
  • @MohammadOmidvar 是的,你说得对,这就是我卡住的地方,尝试了不同的方法来深入了解下一级列表,但无法获取 Emp 列表旁边的数据。

标签: c# json.net restsharp json-deserialization .net-4.8


【解决方案1】:

你的方法有两个问题:

  1. 您希望为不同的类实例反复反序列化相同的源 (response.Content)。它可以反序列化为一种对象类型:您的顶级实体。
  1. 您的数据模型未反映您的数据。例如,YearArray 应该有一个 ProdSale 属性,而不是它们的列表。

您有多种解决方法。让我与您分享两个最常见的:

正确命名

您的对象模型应如下所示:

public class Sale
{
    public string Availability { get; set; }
    public string Reason { get; set; }
}

public class Prod
{
    public string Availability { get; set; }
    public string Reason { get; set; }
}

public class MidLevel
{
    public int Year { get; set; }
    public Sale Sales { get; set; }
    public Prod Top { get; set; }
}

public class TopLevel
{
    public string Employee { get; set; }
    public List<MidLevel> Availability { get; set; } = new List<MidLevel>();
}

那么你需要做的就是调用以下命令:

var result = JsonConvert.DeserializeObject<TopLevel[]>(json);

现在,您的结果将填充所有数据。

JsonProperty

如果您不想在 json 中使用的域模型中使用相同的名称,那么您可以通过 JsonProperty 属性定义这两个世界之间的映射。

现在您的域模型可能如下所示:

public class SalesInformation
{
    [JsonProperty(PropertyName = "availability")]
    public string Avail { get; set; }
    [JsonProperty(PropertyName = "reason")]
    public string Reasoning { get; set; }
}

public class ProdInformation
{
    [JsonProperty(PropertyName = "availability")]
    public string Availability { get; set; }
    [JsonProperty(PropertyName = "reason")]
    public string Reasoning { get; set; }
}

public class MidLevel
{
    [JsonProperty(PropertyName = "year")]
    public int AvailYear { get; set; }
    [JsonProperty(PropertyName = "sales")]
    public SalesInformation SalesInfos { get; set; }
    [JsonProperty(PropertyName = "top")]
    public ProdInformation ProdInfos { get; set; }
}

public class TopLevel
{
    [JsonProperty(PropertyName = "employee")]
    public string Emp { get; set; }
    [JsonProperty(PropertyName = "availability")]
    public List<MidLevel> Availabilities { get; set; } = new List<MidLevel>();
}

用法完全一样:

var result = JsonConvert.DeserializeObject<TopLevel[]>(json);

更新:如何显示数据

在控制台应用程序中表示层次结构可以通过多种方式实现。这里我将使用缩进。我已经介绍了以下小助手方法:

public static void WriteWithIndent(int level, string message) => Console.WriteLine("".PadLeft(level * 2) + message);

有了这个,数据可视化可以通过以下方式实现:

var result = JsonConvert.DeserializeObject<TopLevel[]>(json);
foreach (var topLevel in result)
{
    Console.WriteLine($"Employee: {topLevel.Emp}");
    foreach (var midLevel in topLevel.Availabilities)
    {
        WriteWithIndent(1, $"Year: {midLevel.AvailYear}");
        WriteWithIndent(1, "Sales:");
        WriteWithIndent(2, $"Avail: {midLevel.SalesInfos.Avail}");
        WriteWithIndent(2, $"Reason: {midLevel.SalesInfos.Reasoning}");
        WriteWithIndent(1, "Top:");
        WriteWithIndent(2, $"Avail: {midLevel.ProdInfos.Avail}");
        WriteWithIndent(2, $"Reason: {midLevel.ProdInfos.Reasoning}");
    }
}

打印输出将如下所示:

Employee: 156718100
  Year: 2018
  Sales:
    Avail: Maybe
    Reason:
  Top:
    Avail: Maybe
    Reason:
  Year: 2019
  Sales:
    Avail: Maybe
    Reason:
  Top:
    Avail: Maybe
    Reason:
  Year: 2020
  Sales:
    Avail: Maybe
    Reason:
  Top:
    Avail: Maybe
    Reason:
  Year: 2021
  Sales:
    Avail: Maybe
    Reason:
  Top:
    Avail: Maybe
    Reason:

【讨论】:

  • 非常感谢您的解决方案...是的,它应该是 Prod 而不是 Top。我被困在同一点上,你也指出了如何输出下一级列表。我的更新工作如下: IRestResponse response = client.Execute(request); var 结果 = JsonConvert.DeserializeObject(response.Content); foreach (var rootitem in result) { Console.WriteLine(rootitem.Employee); foreach (var yearitem in rootitem.Availability) { Console.WriteLine("Year: " + yearitem.Year); .... //然后是下一层向下钻取 } }
  • 对于混乱的 cmets 感到抱歉,4 个空格的代码格式在 cmets 中不起作用
  • @Kam 我已经更新了我的答案以包含一些示例代码,这些代码向您展示了如何可视化解析的数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 2019-12-16
  • 1970-01-01
  • 1970-01-01
  • 2019-03-08
相关资源
最近更新 更多