You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中反序列化并获取Report_Data节点的值?

解决Newtonsoft反序列化JSON时的空引用异常及动态Report_Data解析问题

核心问题分析

你的空引用异常大概率来自三个方面:

  1. 实体类属性与JSON字段名未正确映射(比如Type_Report vs TypeReport)
  2. 集合属性未初始化,反序列化后为null
  3. 未正确处理最外层的数组结构

以下是针对性的解决方案,基于Newtonsoft.Json实现,无需修改源JSON结构:


步骤1:定义匹配的实体类

根据你的JSON结构,定义实体类时需注意:

  • 用[JsonProperty]特性严格匹配JSON字段名
  • 初始化集合/对象属性,避免反序列化后为null
  • 对结构动态变化的Report_Data,用JArray存储(Newtonsoft的JSON对象类型,支持灵活解析)
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

// 公司信息实体
public class CompanyInfo
{
    public string Name { get; set; }
    public string Address { get; set; }
}

// 报告项实体
public class ReportItem
{
    [JsonProperty("Type_Report")]
    public string TypeReport { get; set; }

    [JsonProperty("Report_Title")]
    public string ReportTitle { get; set; }

    [JsonProperty("Report_Data")]
    public JArray ReportData { get; set; } = new JArray(); // 初始化避免null
}

// 根对象(外层数组的元素)
public class RootObject
{
    public CompanyInfo CompanyInfo { get; set; } = new CompanyInfo(); // 初始化避免null

    [JsonProperty("ReportsToGenerate")]
    public List<ReportItem> ReportsToGenerate { get; set; } = new List<ReportItem>(); // 初始化避免null
}

步骤2:反序列化并处理数据

反序列化时要注意最外层是数组,需反序列化为List<RootObject>或RootObject[],再遍历解析动态的Report_Data:

方式1:强类型解析(推荐,类型安全)

为不同报告类型定义对应实体类,根据Type_Report的值解析Report_Data:

// 读取JSON文件
string jsonContent = File.ReadAllText("your_report.json");

// 反序列化为数组列表
var rootList = JsonConvert.DeserializeObject<List<RootObject>>(jsonContent);

// 取数组中的唯一对象
var root = rootList.FirstOrDefault();
if (root == null) return;

// 遍历所有报告
foreach (var report in root.ReportsToGenerate)
{
    Console.WriteLine($"报告类型: {report.TypeReport}, 标题: {report.ReportTitle}");

    // 根据报告类型解析Report_Data
    switch (report.TypeReport)
    {
        case "Sales":
            var salesData = report.ReportData.ToObject<List<SalesData>>();
            foreach (var item in salesData)
            {
                Console.WriteLine($"产品: {item.Product}, 营收: {item.Revenue}");
            }
            break;
        case "Inventory":
            var inventoryData = report.ReportData.ToObject<List<InventoryData>>();
            foreach (var item in inventoryData)
            {
                Console.WriteLine($"物品: {item.Item}, 库存: {item.Stock}");
            }
            break;
        default:
            // 未知类型直接输出原始JSON
            Console.WriteLine("未知报告类型,原始数据:");
            Console.WriteLine(report.ReportData.ToString(Formatting.Indented));
            break;
    }
}

// 对应不同报告类型的实体类
public class SalesData
{
    public string Product { get; set; }
    public decimal Revenue { get; set; }
}

public class InventoryData
{
    public string Item { get; set; }
    public int Stock { get; set; }
}

方式2:动态解析(快速原型开发)

如果不想定义多个实体类,可使用dynamic类型直接访问Report_Data的属性:

foreach (var report in root.ReportsToGenerate)
{
    foreach (dynamic dataItem in report.ReportData)
    {
        if (report.TypeReport == "Sales")
        {
            Console.WriteLine($"产品: {dataItem.Product}, 营收: {dataItem.Revenue}");
        }
        else if (report.TypeReport == "Inventory")
        {
            Console.WriteLine($"物品: {dataItem.Item}, 库存: {dataItem.Stock}");
        }
    }
}

空引用异常的预防要点

  • 属性映射:所有JSON字段名与实体类属性名不一致时,必须加[JsonProperty]特性
  • 初始化默认值:集合类(List<T>、JArray)和对象类在实体类中初始化,避免反序列化后为null
  • 空值判断:访问任何可能为null的属性前,先做非空判断(比如root != null、report.ReportData != null)

内容的提问来源于stack exchange,提问作者Arturo Martínez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:15:13