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

自定义Stack Json转换器引发抽象类实例化失败问题求助

问题解决:Stack反序列化顺序修正后出现抽象类无法实例化错误

问题背景

为解决Stack<T>反序列化后元素顺序反转的问题,实现了自定义StackConverter并添加到JsonSerializerSettings中,但出现新错误:

Could not create an instance of type FTest.Total. Type is an interface or abstract class and cannot be instantiated. Path 'Basket.Totals[0].Value', line 17, position 16.

错误原因

你的JSON数据中包含$type字段(如"$type": "FTest.PointTargetAmount, FTest.Basket"),用于指定抽象类Total的具体实现类型,但当前JsonSerializerSettings中**TypeNameHandling被注释禁用**,导致在StackConverter的ReadJsonGeneric方法里调用serializer.Deserialize<List<T>>时,Json.NET无法识别$type信息,尝试直接实例化抽象类Total,从而抛出错误。

解决方案

方案1:启用TypeNameHandling

在JsonSerializerSettings中取消TypeNameHandling的注释,设置为Auto,让Json.NET自动识别并利用$type字段创建具体类型实例:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddJsonOptions(opt =>
        {
            opt.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
            // 取消注释并启用TypeNameHandling
            opt.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
            opt.SerializerSettings.DateParseHandling = Newtonsoft.Json.DateParseHandling.DateTimeOffset;
            opt.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.IsoDateFormat;
            opt.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.RoundtripKind;
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            opt.SerializerSettings.ConstructorHandling = Newtonsoft.Json.ConstructorHandling.AllowNonPublicDefaultConstructor;
            opt.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
            opt.SerializerSettings.Converters.Add(new StackConverter());
        });

方案2:修改StackConverter以兼容类型信息(可选)

如果不想全局启用TypeNameHandling,可以修改ReadJsonGeneric方法,在反序列化列表时显式传递类型,确保Json.NET能处理$type字段:

object ReadJsonGeneric<T>(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.Null)
        return null;
    // 改用Deserialize的重载,指定类型,确保类型信息被处理
    var list = serializer.Deserialize(reader, typeof(List<T>)) as List<T>;
    var stack = existingValue as Stack<T> ?? (Stack<T>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
    for (int i = list.Count - 1; i >= 0; i--)
        stack.Push(list[i]);
    return stack;
}

注意:此方案仍需确保TypeNameHandling未被设置为None,否则依然无法识别$type字段。

补充说明

  • TypeNameHandling.Auto会在序列化多态类型时自动添加$type字段,反序列化时也会读取该字段创建正确的具体实例,正好匹配你的JSON数据格式。
  • 若担心类型注入安全问题,可以配合SerializationBinder限制允许反序列化的类型范围。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:23:13