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

如何在Json.NET中为二叉树节点序列化添加前后自定义代码?

解决Json.NET自定义Node转换器的无限递归问题

嘿,我明白你遇到的问题了——在自定义JsonConverter的WriteJson方法里调用serializer.Serialize,结果触发了无限递归,对吧?这其实是个很典型的陷阱,因为你已经把NodeConverter添加到序列化器的转换器列表里了,每次调用serializer.Serialize处理Node类型时,都会优先用你的转换器,于是就循环调用WriteJson没完没了。

不过别担心,完全可以实现“每个Node序列化前后执行自定义代码”的需求,下面给你两种靠谱的方案,看你更倾向哪种:


方案一:手动序列化节点属性(推荐,精准控制每个节点)

这个方案最适合你的需求,因为它能让**每个Node(包括根节点和所有子节点)**都执行前后的自定义代码,同时避免无限递归。核心思路是:不要直接序列化整个Node对象,而是手动逐个序列化它的Data、Left、Right属性,这样既不会触发递归调用转换器,又能让子节点的序列化自然触发转换器的逻辑。

首先,先把你的Node类的属性改成公开的(不然默认序列化访问不到私有成员):

public class Node 
{ 
    public Node Left { get; set; } 
    public Node Right { get; set; } 
    public int Data { get; set; } 
}

然后修改你的自定义转换器:

public class NodeConverter : JsonConverter 
{
    public override bool CanConvert(Type objectType) 
    { 
        return objectType == typeof(Node); 
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
        throw new NotImplementedException(); // 如果你需要反序列化,再实现这里
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    {
        var node = value as Node;
        if (node == null)
        {
            writer.WriteNull();
            return;
        }

        // 每个Node序列化前的自定义逻辑
        Console.WriteLine($"Before serializing Node with Data: {node.Data}");

        // 手动构建Node的JSON结构
        writer.WriteStartObject();
        
        // 序列化Data(int类型不会触发转换器)
        writer.WritePropertyName("Data");
        serializer.Serialize(writer, node.Data);

        // 序列化Left节点——这里会触发当前转换器,递归执行Before/After逻辑
        writer.WritePropertyName("Left");
        serializer.Serialize(writer, node.Left);

        // 序列化Right节点,同理递归处理
        writer.WritePropertyName("Right");
        serializer.Serialize(writer, node.Right);

        writer.WriteEndObject();

        // 每个Node序列化后的自定义逻辑
        Console.WriteLine($"After serializing Node with Data: {node.Data}");
    }
}

这样运行你的代码后,每个节点都会输出对应的Before/After日志,同时生成正确的二叉树JSON结构,完全不会有无限递归的问题。


方案二:临时移除转换器(适合仅根节点执行前后逻辑)

如果你只需要在整个树的根节点序列化前后执行自定义代码,而子节点不需要,那可以用这个方案:临时从序列化器的转换器列表中移除当前的NodeConverter,序列化完成后再加回来。

修改后的WriteJson方法:

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    Console.WriteLine("Before serializing root node");

    // 临时移除当前转换器
    var currentConverter = serializer.Converters.FirstOrDefault(c => c is NodeConverter);
    if (currentConverter != null)
    {
        serializer.Converters.Remove(currentConverter);
        // 此时序列化Node会用默认逻辑,不会触发转换器
        serializer.Serialize(writer, value);
        // 把转换器加回去,不影响后续其他序列化操作
        serializer.Converters.Add(currentConverter);
    }
    else
    {
        // 理论上不会走到这里,保险起见直接序列化
        serializer.Serialize(writer, value);
    }

    Console.WriteLine("After serializing root node");
}

这个方案要注意:如果是多线程环境下使用同一个序列化器,临时移除/添加转换器可能会有线程安全问题,单线程场景下完全没问题。


最后,你的使用代码可以保持不变,只要确保CreateTree方法返回的是正确构建的二叉树就行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:55:58