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

如何仅对字符串Token执行JsonConverter避免JSON.NET反序列化死循环

问题根源

你遇到的无限循环是因为调用serializer.Deserialize时,序列化器会优先使用已注册的ReferenceJsonConverter处理NamedType类型,就算当前Token是对象类型也会再次进入你的Converter逻辑,形成递归死循环。

可行解决方案

这里提供两种可直接落地的实现,优先推荐第一种,无并发风险:

方案1:创建无当前Converter的独立序列化器反序列化对象

在遇到非字符串Token时,先加载当前节点为JToken,再使用拷贝了原序列化器所有配置、但移除了ReferenceJsonConverter的新序列化器来反序列化,避免触发当前Converter:

public class ReferenceJsonConverter : JsonConverter<NamedType>
{
    private readonly ContentLoader _contentLoader;
    
    public ReferenceJsonConverter(ContentLoader contentLoader)
    {
        _contentLoader = contentLoader;
    }

    public override bool CanWrite => false;

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

    public override NamedType ReadJson(JsonReader reader, Type objectType, NamedType existingValue, bool hasExistingValue,
        JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        // 字符串类型走引用加载逻辑
        if (token.Type == JTokenType.String)
        {
            string value = token.Value<string>().ToLower();
            return _contentLoader.Load<NamedType>(value);
        }
        // 非字符串类型使用默认反序列化,新序列化器不加入当前Converter避免循环
        var newSerializer = new JsonSerializer();
        // 同步原有序列化器的所有配置和其他Converter
        foreach (var converter in serializer.Converters.Where(c => c != this))
        {
            newSerializer.Converters.Add(converter);
        }
        newSerializer.ContractResolver = serializer.ContractResolver;
        newSerializer.Formatting = serializer.Formatting;
        newSerializer.NullValueHandling = serializer.NullValueHandling;
        newSerializer.DefaultValueHandling = serializer.DefaultValueHandling;
        // 其他你用到的自定义序列化配置可按需同步
        return token.ToObject<NamedType>(newSerializer);
    }
}

方案2:临时禁用当前Converter(仅单线程场景可用)

如果你的序列化器是单线程独占使用的,可以临时把当前Converter从集合中移除,反序列化完成后再加回来:

public override NamedType ReadJson(JsonReader reader, Type objectType, NamedType existingValue, bool hasExistingValue,
    JsonSerializer serializer)
{
    switch (reader.TokenType)
    {
        case JsonToken.String:
        {
            string value = reader.Value!.ToString().ToLower();
            return _contentLoader.Load<NamedType>(value);
        }
        default:
        {
            serializer.Converters.Remove(this);
            try
            {
                return (NamedType?) serializer.Deserialize(reader, objectType);
            }
            finally
            {
                serializer.Converters.Add(this);
            }
        }
    }
}

效果验证

两种方案都完全符合你的需求:

  • 当NamedType类型的字段值为字符串时,走自定义引用加载逻辑
  • 当NamedType类型的字段值为JSON对象时,走默认反序列化流程,不会触发无限循环

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 02:03:01