如何在C#中反序列化并获取Report_Data节点的值?
解决Newtonsoft反序列化JSON时的空引用异常及动态Report_Data解析问题
核心问题分析
你的空引用异常大概率来自三个方面:
- 实体类属性与JSON字段名未正确映射(比如
Type_ReportvsTypeReport) - 集合属性未初始化,反序列化后为
null - 未正确处理最外层的数组结构
以下是针对性的解决方案,基于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
相关产品推荐
相关产品推荐

