如何向单个数组添加不同JSON对象?C#模型适配方案咨询
问题背景
我有一个键名为IssuesList的JSON对象,其值是由对象组成的JSON数组,但该数组存在两种不同结构的对象:
常规结构
"IssuesList": [ { "IssueOrderNumber": 1, "Description": "Houston, we have a problem.", "Resolution": "We are working on it.", "Severity": 1 }, ... ]
特殊结构(OSHA事件)
"IssuesList": [ { "EventDate": "2023-12-20", "RecordClassificationTypeSelected": "In-patient hospitalization for medical treatment", "InjuryIllnessDescription": null }, ... ]
当前代码无法编译,因为特殊场景下issue参数类型不匹配:
public int AddToIssuesList(string companyid, string templateid, string pageid, int metadatatypeid, string requestorId, IssuesList issue) { try { using (var db = new DbContext(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)) { string wholeJsonData = PageDataRequiringValidation(metadatatypeid, null, null, null, companyid, requestorId); var objWholeJsonData = JsonConvert.DeserializeObject<Rootobject>(wholeJsonData); var objPage = objWholeJsonData.Pages.FirstOrDefault(x => x.PageId == pageid); objPage.PageData.IssuesList.Add(issue); var updatedWholeJsonData = JsonConvert.SerializeObject(objWholeJsonData); // TODO: Write to DB return 1; } } catch (Exception ex) { return 0; } }
现有模型定义:
public class IssuesList { public int IssueOrderNumber { get; set; } public string Description { get; set; } public string Resolution { get; set; } public string Severity { get; set; } = null; } public class OSHAIncidentsList { [JsonProperty("IssuesList")] public string EventDate { get; set; } public string RecordClassificationTypeSelected { get; set; } public string InjuryIllnessDescription { get; set; } }
目前考虑通过前端传入标识来分支处理参数反序列化,但想了解是否有更优的处理方案。
优化解决方案
方案1:自定义JsonConverter自动识别类型
通过Newtonsoft.Json的自定义转换器,在反序列化时根据JSON中的字段自动判断对象类型,无需前端额外传标识。
步骤1:定义基类
public abstract class BaseIssue { // 若有公共字段可在此定义 } public class IssuesList : BaseIssue { public int IssueOrderNumber { get; set; } public string Description { get; set; } public string Resolution { get; set; } public string Severity { get; set; } = null; } public class OSHAIncidentsList : BaseIssue { public string EventDate { get; set; } public string RecordClassificationTypeSelected { get; set; } public string InjuryIllnessDescription { get; set; } }
步骤2:实现自定义转换器
public class IssueConverter : JsonConverter<BaseIssue> { public override BaseIssue ReadJson(JsonReader reader, Type objectType, BaseIssue existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); // 根据特征字段判断类型:常规Issue含IssueOrderNumber,OSHA事件含EventDate if (jsonObj.ContainsKey("IssueOrderNumber")) { return jsonObj.ToObject<IssuesList>(serializer); } else if (jsonObj.ContainsKey("EventDate")) { return jsonObj.ToObject<OSHAIncidentsList>(serializer); } throw new JsonSerializationException("无法识别的Issue类型"); } public override void WriteJson(JsonWriter writer, BaseIssue value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
步骤3:在模型中应用转换器
修改Rootobject中PageData的IssuesList属性定义:
public class PageData { [JsonConverter(typeof(IssueConverter))] public List<BaseIssue> IssuesList { get; set; } }
步骤4:调整业务方法参数
将方法参数改为基类BaseIssue,自动兼容两种类型:
public int AddToIssuesList(string companyid, string templateid, string pageid, int metadatatypeid, string requestorId, BaseIssue issue) { try { using (var db = new DbContext(System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)) { string wholeJsonData = PageDataRequiringValidation(metadatatypeid, null, null, null, companyid, requestorId); var objWholeJsonData = JsonConvert.DeserializeObject<Rootobject>(wholeJsonData); var objPage = objWholeJsonData.Pages.FirstOrDefault(x => x.PageId == pageid); objPage.PageData.IssuesList.Add(issue); var updatedWholeJsonData = JsonConvert.SerializeObject(objWholeJsonData); // TODO: Write to DB return 1; } } catch (Exception ex) { return 0; } }
方案2:动态类型临时处理
如果不想修改现有模型结构,可以用JObject/JArray动态解析JSON,判断类型后再转换:
// 反序列化时先转为JObject var objWholeJsonData = JsonConvert.DeserializeObject<JObject>(wholeJsonData); var objPage = objWholeJsonData["Pages"].FirstOrDefault(x => x["PageId"].ToString() == pageid); var issuesList = objPage["PageData"]["IssuesList"] as JArray; // 根据传入的issue类型转换为JObject添加 if (issue is IssuesList regularIssue) { issuesList.Add(JObject.FromObject(regularIssue)); } else if (issue is OSHAIncidentsList oshaIssue) { issuesList.Add(JObject.FromObject(oshaIssue)); } // 序列化回字符串 var updatedWholeJsonData = objWholeJsonData.ToString();
这种方式无需修改模型,但无类型安全检查,适合临时快速修复。
方案3:合并成单模型(可选字段)
如果两种结构无冲突字段,可合并为一个模型,所有字段设为可选:
public class CombinedIssue { // 常规Issue字段 public int? IssueOrderNumber { get; set; } public string Description { get; set; } public string Resolution { get; set; } public string Severity { get; set; } // OSHA事件字段 public string EventDate { get; set; } public string RecordClassificationTypeSelected { get; set; } public string InjuryIllnessDescription { get; set; } }
将IssuesList定义为List<CombinedIssue>即可兼容两种结构,但模型语义模糊,可读性较差,仅适合结构差异极小的场景。
方案对比与推荐
- 自定义JsonConverter:类型安全、扩展性强,无需前端额外传参,自动识别类型,是长期维护的最优方案。
- 动态类型:实现快速,但无类型检查,后期维护风险高,适合临时修复。
- 合并模型:实现最简单,但模型语义模糊,字段过多时易混淆,仅适合结构差异极小的场景。
内容的提问来源于stack exchange,提问作者Nosnetrom
相关产品推荐
相关产品推荐

