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

如何向单个数组添加不同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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:53:16