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

自定义JsonConverter实现继承类列表的序列化与反序列化问题

问题描述

类结构

// 父类
public class Circle
{
    public decimal Area { get; set; } = 0.2m;
}

// 子类
public class GreenCircle : Circle
{
    public string Color { get; set; } = "Green";
}

public class RedCircle : Circle
{
    public string Color { get; set; } = "Red";
}

public class BlueCircle : Circle
{
    public string Color { get; set; } = "Blue";
}

// 待转换类
public class Shapes
{
    public string ShapeType { get; set; } = "Circle";
    public List<Circle> ShapeList { get; set; } = new List<Circle>
    {
        new RedCircle(),
        new BlueCircle(),
        new GreenCircle(),
    };
}

目标JSON格式

{
  "shapeType": "circle",
  "shapeList": [
    {"name": "RedCircle",  "color": "red", "area": 0.2},
    {"name": "BlueCircle",  "color": "blue", "area": 0.2},
    {"name": "GreenCircle",  "color": "green", "area": 0.2}
  ]
}

疑问

  • 如何反序列化包含普通字段和数组字段的JSON?
  • 是否可以直接将列表反序列化为子类对象?(即列表中包含RedCircle、BlueCircle和GreenCircle对象,而非3个Circle对象)

解决方案

要实现需求,确实需要自定义JsonConverter处理多态序列化/反序列化,以下是完整实现方案:

1. 自定义Circle类型的JsonConverter

该转换器负责单个Circle子类的序列化与反序列化,通过JSON中的name字段识别具体子类:

public class CircleConverter : JsonConverter<Circle>
{
    // 序列化:将Circle子类转为指定格式的JSON对象
    public override void WriteJson(JsonWriter writer, Circle value, JsonSerializer serializer)
    {
        JObject obj = new JObject();
        // 写入类型名称
        obj.Add("name", value.GetType().Name);
        // 写入Area字段
        obj.Add("area", value.Area);
        // 写入Color字段(仅子类处理)
        if (value is GreenCircle green)
            obj.Add("color", green.Color.ToLower());
        else if (value is RedCircle red)
            obj.Add("color", red.Color.ToLower());
        else if (value is BlueCircle blue)
            obj.Add("color", blue.Color.ToLower());
        obj.WriteTo(writer);
    }

    // 反序列化:根据name字段创建对应子类实例并填充属性
    public override Circle ReadJson(JsonReader reader, Type objectType, Circle existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        string name = obj["name"].ToString();
        
        // 根据name创建对应子类实例
        Circle circle = name switch
        {
            "RedCircle" => new RedCircle(),
            "BlueCircle" => new BlueCircle(),
            "GreenCircle" => new GreenCircle(),
            _ => new Circle()
        };

        // 填充Area字段
        circle.Area = obj["area"].ToObject<decimal>();
        // 填充Color字段(仅子类处理)
        if (circle is RedCircle red)
            red.Color = obj["color"].ToString().ToUpper();
        else if (circle is BlueCircle blue)
            blue.Color = obj["color"].ToString().ToUpper();
        else if (circle is GreenCircle green)
            green.Color = obj["color"].ToString().ToUpper();

        return circle;
    }
}

2. 配置序列化/反序列化选项

通过JsonSerializerOptions添加自定义转换器,并处理属性名的大小写转换:

// 序列化示例
Shapes shapes = new Shapes();
var serializeOptions = new JsonSerializerOptions
{
    Converters = { new CircleConverter() },
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // 自动转换为小驼峰命名
    WriteIndented = true
};
string json = JsonSerializer.Serialize(shapes, serializeOptions);

// 反序列化示例
string jsonStr = @"{""shapeType"":""circle"",""shapeList"":[{""name"":""RedCircle"",""color"":""red"",""area"":0.2},{""name"":""BlueCircle"",""color"":""blue"",""area"":0.2},{""name"":""GreenCircle"",""color"":""green"",""area"":0.2}]}";
var deserializeOptions = new JsonSerializerOptions
{
    Converters = { new CircleConverter() },
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
Shapes deserializedShapes = JsonSerializer.Deserialize<Shapes>(jsonStr, deserializeOptions);

// 验证反序列化结果:输出各元素的类型名称
foreach (var item in deserializedShapes.ShapeList)
{
    Console.WriteLine(item.GetType().Name); // 依次输出RedCircle、BlueCircle、GreenCircle
}

疑问解答

  1. 反序列化包含普通字段和数组字段的JSON:
    只需配置正确的序列化选项(如小驼峰命名匹配),并为数组元素类型添加自定义转换器,JsonSerializer会自动处理普通字段(如ShapeType)和数组字段(如ShapeList)的反序列化,无需额外编写普通字段的处理逻辑。

  2. 将列表反序列化为子类对象:
    通过自定义JsonConverter<Circle>,在ReadJson方法中根据name字段创建对应的子类实例并填充属性,最终ShapeList中的元素会是RedCircle、BlueCircle、GreenCircle的实例,而非基类Circle。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:47:17