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

如何在C#中通过Newtonsoft根据Type属性反序列化动态Data节点

基于Newtonsoft.Json根据Type属性反序列化多态Data节点的解决方案

问题背景

开发C#应用时,API返回的JSON中Block节点下的Data结构多变,仅共用Type属性,需要根据Type将Data反序列化为对应的具体类,以兼容所有数据类型并能通过Type判断对象类型。

API返回的JSON示例:

{
    "nextLink": "NextLink",
    "value": [
        {
            "Block": {
                "BlockName": "Name",
                "BlockClass": "Class",
                "IsVisibile": true,
                "Data": {
                    "Type": "Footer",
                    "Values": [
                        { 
                            "Property1": "Property1",
                            "Property2": "Property2"
                        }
                    ],
                    "Show": false
                }
            }
        },
        {
            "Block": {
                "BlockName": "Name",
                "BlockClass": "Class",
                "IsVisibile": true,
                "Data": {
                    "Type": "Header",
                    "Title": "Main title",
                    "Subtitle": "Subtitle"
                }
            }
        },
        {
            "Block": {
                "BlockName": "Name",
                "BlockClass": "Class",
                "IsVisibile": true,
                "Data": {
                    "Type": "Body",
                    "Information": "Info",
                    "AdditionalText": "More text",
                    "Projects": [
                        "Project1",
                        "Project2"
                    ]
                }
            }
        }
    ]
}

现有类定义(需修改):

public class Blocks
{
    public string NextLink { get; set; }
    public Response[] Value { get; set; }
}

public class Response
{
    public Block Block { get; set; }
}

public class Block
{
    public string BlockName { get; set; }
    public string BlockClass { get; set; }
    public bool IsVisible { get; set; }
    public Data Data { get; set; }
}

public class Data 
{
    public string Type { get; set; }
}

public class FooterType
{
    public bool Show { get; set; }
    public object[] Values { get; set; }
}

public class HeaderType 
{
    public string Title { get; set; }
    public string Subtitle { get; set; }
}

public class BodyType
{
    public string Information { get; set; }
    public string AdditionalText { get; set; }
    public object[] Projects { get; set; }
}

解决方案

方案一:使用Newtonsoft.Json.Subtypes扩展包(推荐)

该方案通过特性配置多态映射,代码简洁易维护。

  1. 安装扩展包
    通过NuGet安装Newtonsoft.Json.Subtypes:
Install-Package Newtonsoft.Json.Subtypes
  1. 修改类结构
    将Data改为抽象基类,并通过特性指定Type与子类的映射关系;所有数据子类继承Data:
// 配置多态映射,基于Type属性匹配子类
[JsonConverter(typeof(JsonSubtypes), nameof(Type))]
[JsonSubtypes.KnownSubType(typeof(FooterType), "Footer")]
[JsonSubtypes.KnownSubType(typeof(HeaderType), "Header")]
[JsonSubtypes.KnownSubType(typeof(BodyType), "Body")]
public abstract class Data
{
    public string Type { get; set; }
}

// 子类继承Data基类
public class FooterType : Data
{
    public bool Show { get; set; }
    public object[] Values { get; set; }
}

public class HeaderType : Data
{
    public string Title { get; set; }
    public string Subtitle { get; set; }
}

public class BodyType : Data
{
    public string Information { get; set; }
    public string AdditionalText { get; set; }
    public object[] Projects { get; set; }
}
  1. 反序列化与类型判断
    直接使用默认反序列化方法,之后可通过Type属性或类型转换判断具体对象:
// 反序列化API响应
string apiJson = // 从API获取的JSON字符串
var blocks = JsonConvert.DeserializeObject<Blocks>(apiJson);

// 遍历并处理不同类型的Data
foreach (var response in blocks.Value)
{
    var data = response.Block.Data;
    switch (data.Type)
    {
        case "Footer":
            var footerData = data as FooterType;
            // 使用footerData的Show、Values等属性
            break;
        case "Header":
            var headerData = data as HeaderType;
            // 使用headerData的Title、Subtitle等属性
            break;
        case "Body":
            var bodyData = data as BodyType;
            // 使用bodyData的Information、Projects等属性
            break;
        default:
            // 处理未知类型
            break;
    }
}

方案二:自定义Json转换器(无额外依赖)

若不想引入扩展包,可自定义转换器实现多态反序列化。

  1. 编写自定义转换器
    创建继承自JsonConverter<Data>的转换器类,在ReadJson方法中根据Type值选择对应子类:
public class DataConverter : JsonConverter<Data>
{
    public override Data ReadJson(JsonReader reader, Type objectType, Data existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 加载JSON对象
        var jObject = JObject.Load(reader);
        // 获取Type属性值
        var type = jObject["Type"].Value<string>();

        // 根据Type反序列化为对应子类
        return type switch
        {
            "Footer" => jObject.ToObject<FooterType>(serializer),
            "Header" => jObject.ToObject<HeaderType>(serializer),
            "Body" => jObject.ToObject<BodyType>(serializer),
            _ => throw new NotSupportedException($"不支持的Data类型:{type}")
        };
    }

    public override void WriteJson(JsonWriter writer, Data value, JsonSerializer serializer)
    {
        // 序列化时直接输出对象内容
        serializer.Serialize(writer, value);
    }
}
  1. 配置转换器
    有两种方式启用转换器:
  • 方式一:在Data类上添加特性:
[JsonConverter(typeof(DataConverter))]
public abstract class Data
{
    public string Type { get; set; }
}
  • 方式二:反序列化时传入配置:
var settings = new JsonSerializerSettings();
settings.Converters.Add(new DataConverter());
var blocks = JsonConvert.DeserializeObject<Blocks>(apiJson, settings);
  1. 类型判断与使用
    与方案一一致,通过Type属性或类型转换处理不同子类对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:10:02