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

ASP.NET Core中如何无类型字段反序列化JSON到派生类?

问题描述

前端生成的RuleGroup JSON结构如下(包含嵌套的RuleGroup和RuleCriteria节点):

{
  "combinator": "OR",
  "not": true,
  "criteria": [
    {
      "field": "path",
      "key": "",
      "value": "",
      "operator": "="
    },
    {
      "combinator": "AND",
      "not": false,
      "criteria": [
        {
          "field": "header",
          "key": "",
          "value": "",
          "operator": "="
        }
      ]
    }
  ]
}

对应的C#类型定义如下,但反序列化时Criteria列表中的元素均被序列化为BaseRule基类对象,无法转换为对应的派生类:

public class RuleGroup : BaseRule
{
    public string Combinator { get; set; }
    public bool Not { get; set; }
    public List<BaseRule> Criteria { get; set; }
}

public class RuleCriteria : BaseRule
{
    public string Field { get; set; }
    public string Operator { get; set; }
    public string Key { get; set; }
    public string Value { get; set; }
}

public class BaseRule
{
}

不想为JSON数据添加专用类型鉴别字段,也不想手动编写完整的反序列化器,询问是否有其他可行的实现方式。

解决方案

无需手动编写完整反序列化逻辑,可通过基于属性存在性的自定义类型转换器实现多态反序列化,以下是两种主流JSON库的实现方案:

1. 使用Newtonsoft.Json(Json.NET)

自定义转换器,通过判断JSON对象中是否包含combinator或field属性来区分派生类:

public class BaseRuleConverter : JsonConverter<BaseRule>
{
    public override BaseRule ReadJson(JsonReader reader, Type objectType, BaseRule existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        
        // 包含combinator属性则实例化RuleGroup
        if (jObject.ContainsKey("combinator"))
        {
            var ruleGroup = new RuleGroup();
            serializer.Populate(jObject.CreateReader(), ruleGroup);
            return ruleGroup;
        }
        // 包含field属性则实例化RuleCriteria
        else if (jObject.ContainsKey("field"))
        {
            var criteria = new RuleCriteria();
            serializer.Populate(jObject.CreateReader(), criteria);
            return criteria;
        }
        
        throw new JsonSerializationException("无法识别的BaseRule类型");
    }

    public override void WriteJson(JsonWriter writer, BaseRule value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

使用方式二选一:

  • 在BaseRule类上标记转换器:
    [JsonConverter(typeof(BaseRuleConverter))]
    public class BaseRule
    {
    }
    
  • 反序列化时指定转换器:
    var ruleGroup = JsonConvert.DeserializeObject<RuleGroup>(jsonString, new BaseRuleConverter());
    

2. 使用System.Text.Json

自定义转换器,通过JsonElement判断属性存在性:

public class BaseRuleConverter : JsonConverter<BaseRule>
{
    public override BaseRule Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using (var doc = JsonDocument.ParseValue(ref reader))
        {
            var root = doc.RootElement;
            
            if (root.TryGetProperty("combinator", out _))
            {
                return JsonSerializer.Deserialize<RuleGroup>(root.GetRawText(), options);
            }
            else if (root.TryGetProperty("field", out _))
            {
                return JsonSerializer.Deserialize<RuleCriteria>(root.GetRawText(), options);
            }
            
            throw new JsonException("无法识别的BaseRule类型");
        }
    }

    public override void Write(Utf8JsonWriter writer, BaseRule value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}

使用方式二选一:

  • 在序列化配置中添加转换器:
    var options = new JsonSerializerOptions();
    options.Converters.Add(new BaseRuleConverter());
    var ruleGroup = JsonSerializer.Deserialize<RuleGroup>(jsonString, options);
    
  • 在BaseRule类上标记转换器:
    [JsonConverter(typeof(BaseRuleConverter))]
    public class BaseRule
    {
    }
    

以上方案会自动根据JSON中的属性特征判断实例化对应派生类,无需额外类型字段,也不用编写完整的反序列化逻辑。

内容的提问来源于stack exchange,提问作者Darc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:23:26