使用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
相关产品推荐
相关产品推荐

