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

使用System.Text.Json序列化派生类时遭遇CastException的解决方法

解决System.Text.Json序列化派生类时自定义转换器的类型转换异常

问题原因

当你为基类Image定义了自定义转换器ImageConverter,但序列化List<DerivedImage>(DerivedImage继承自Image)时,System.Text.Json尝试将ImageConverter强制转换为JsonConverter<DerivedImage>,由于泛型类型不匹配,抛出InvalidCastException。

解决方案

方案1:将自定义转换器改为非泛型JsonConverter并实现CanConvert

重写转换器,让它支持所有Image的派生类:

public class ImageConverter : JsonConverter
{
    // 判断当前类型是否是Image或其派生类
    public override bool CanConvert(Type typeToConvert)
    {
        return typeof(Image).IsAssignableFrom(typeToConvert);
    }

    // 反序列化逻辑
    public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 示例:根据JSON中的标识字段判断具体类型
        using var doc = JsonDocument.ParseValue(ref reader);
        var type = doc.RootElement.GetProperty("Type").GetString();
        
        return type switch
        {
            "DerivedImage" => JsonSerializer.Deserialize<DerivedImage>(doc.RootElement.GetRawText(), options),
            _ => JsonSerializer.Deserialize<Image>(doc.RootElement.GetRawText(), options)
        };
    }

    // 序列化逻辑
    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        var image = (Image)value;
        // 写入基类及派生类的属性
        writer.WriteStartObject();
        writer.WriteString("Type", value.GetType().Name);
        writer.WriteString("ImageUrl", image.ImageUrl);
        // 写入派生类特有的属性(如果需要)
        if (value is DerivedImage derived)
        {
            writer.WriteInt32("Width", derived.Width);
        }
        writer.WriteEndObject();
    }
}

然后在序列化配置中添加该转换器:

var options = new JsonSerializerOptions();
options.Converters.Add(new ImageConverter());

// 序列化List<DerivedImage>
var json = JsonSerializer.Serialize(derivedImageList, options);

方案2:在派生类上标注JsonConverter特性

直接在DerivedImage类上指定使用基类的转换器:

[JsonConverter(typeof(ImageConverter))]
public class DerivedImage : Image
{
    // 派生类成员
}

这样序列化List<DerivedImage>时,会自动使用ImageConverter处理每个元素,无需额外配置转换器(如果转换器是泛型JsonConverter<Image>也适用)。

方案3:泛型转换器适配派生类

如果坚持使用泛型转换器,可将其定义为支持所有Image子类:

public class ImageConverter<T> : JsonConverter<T> where T : Image
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 反序列化逻辑,返回T类型实例
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        // 序列化逻辑
    }
}

然后在配置中为Image和DerivedImage分别添加转换器:

var options = new JsonSerializerOptions();
options.Converters.Add(new ImageConverter<Image>());
options.Converters.Add(new ImageConverter<DerivedImage>());

但这种方式需要为每个派生类单独注册转换器,灵活性不如方案1。

内容的提问来源于stack exchange,提问作者L. Berger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:53:13