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

自定义JsonConverter仅反序列化Actions属性失败,求解决方案

问题描述

我正在处理如下复杂JSON结构的反序列化,其中events下的id代表对应事件:

"events": [
{
    "id": 1,
    "actions": [
    {
        "id": 8,
        "values": {
            "obj_id":160,
            "url": "https://www.myurl.com/"
        }
    },
    {
        "id":15,
        "values":{
            "obj_id":182,
            "scale":200
        }
    }
    ]
}
]

我定义了抽象类ActionBase及多个派生类,不同的action id对应不同的values类型,相关C#类结构如下:

public class Events
{
    public int id;
    public ActionsHolder[] actions;
}

[JsonConverter(typeof(BaseConverter))]
public class ActionsHolder
{
    public int id { get; set; } = -1;
    public ActionBase values { get; set; }
}

public abstract class ActionBase : ActionsHolder
{
    public int obj_id { get; set; }
}

public class OpenURLAction : ActionBase
{
    //Action id 8 = Open URL
    public string url { get; set; }
}

public class ScaleAction : ActionBase
{
    //Action id 15 = Scale
    public float scale { get; set; } = 1;
}

同时编写了自定义JsonConverter代码:

public class BaseSpecifiedConcreteClassConverter : DefaultContractResolver
{
    protected override JsonConverter ResolveContractConverter(Type objectType)
    {
        if (typeof(ActionsHolder).IsAssignableFrom(objectType) && !objectType.IsAbstract)
        {
            return null; 
        }
            
        return base.ResolveContractConverter(objectType);
    }
}

public class BaseConverter : JsonConverter
{
    static JsonSerializerSettings SpecifiedSubclassConversion = new JsonSerializerSettings() 
    { 
        ContractResolver = new BaseSpecifiedConcreteClassConverter() ,
        TypeNameHandling = TypeNameHandling.All
    };

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(ActionsHolder));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject joAction = JObject.Load(reader);

        JObject joValues = (JObject)joAction["values"];
        switch (joAction["id"].Value<int>())
        {
            case 8:
                return new ActionsHolder
                {
                    id = joAction["id"].Value<int>(),
                    values = JsonConvert.DeserializeObject<OpenURLAction>(joValues.ToString(), SpecifiedSubclassConversion)
                };
            case 15:
                return new ActionsHolder
                {
                    id = joAction["id"].Value<int>(),
                    values = JsonConvert.DeserializeObject<ScaleAction>(joValues.ToString(), SpecifiedSubclassConversion)
                };
            default:
                return null;
        }
        throw new NotImplementedException();
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

但目前该实现无法正常工作,我希望让自定义转换器仅处理actions属性,其余属性使用默认转换器,请问该如何修正?


修正方案

1. 修复ActionBase的继承关系(核心修复)

原代码中ActionBase继承自ActionsHolder属于逻辑错误,会导致类型嵌套递归,直接修改ActionBase为独立抽象类:

public abstract class ActionBase
{
    public int obj_id { get; set; }
}

2. 移除ActionsHolder类上的全局转换器标记

把ActionsHolder类上的[JsonConverter(typeof(BaseConverter))]特性删除,避免全局强制使用该转换器:

public class ActionsHolder
{
    public int id { get; set; } = -1;
    public ActionBase values { get; set; }
}

3. 给Events的actions属性单独指定转换器

在Events类的actions字段上添加特性,仅让该属性的元素使用自定义转换器:

public class Events
{
    public int id;
    [JsonProperty(ItemConverterType = typeof(BaseConverter))]
    public ActionsHolder[] actions;
}

4. 简化自定义转换器逻辑

移除多余的TypeNameHandling和自定义契约解析器,直接通过action id匹配派生类型:

public class BaseConverter : JsonConverter<ActionsHolder>
{
    public override ActionsHolder ReadJson(JsonReader reader, Type objectType, ActionsHolder existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JObject joAction = JObject.Load(reader);
        var holder = new ActionsHolder();
        // 用默认序列化逻辑处理id属性
        serializer.Populate(joAction.CreateReader(), holder);
        
        int actionId = joAction["id"].Value<int>();
        JObject joValues = (JObject)joAction["values"];
        
        switch (actionId)
        {
            case 8:
                holder.values = joValues.ToObject<OpenURLAction>(serializer);
                break;
            case 15:
                holder.values = joValues.ToObject<ScaleAction>(serializer);
                break;
            default:
                throw new NotSupportedException($"不支持的Action ID: {actionId}");
        }
        
        return holder;
    }

    public override void WriteJson(JsonWriter writer, ActionsHolder value, JsonSerializer serializer)
    {
        // 若不需要序列化可抛出异常,或按需实现序列化逻辑
        throw new NotImplementedException();
    }
}

5. 正常执行反序列化

现在直接用默认配置反序列化即可,自定义转换器只会作用于actions数组的元素:

var eventsList = JsonConvert.DeserializeObject<List<Events>>(yourJsonString);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:23:26