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

使用Newtonsoft Json序列化含循环引用的Car类及自定义转换器需求

解决方案:自定义Json转换器控制Car1属性的序列化

当然可以通过自定义Json转换器来解决这个问题!核心逻辑就是在序列化Car对象时,先检查它的Id属性值:如果Id为0,就跳过Car1属性的序列化;如果Id非0,则正常处理所有属性。

1. 实现自定义Json转换器

创建一个继承自JsonConverter<Car>的转换器,重写WriteJson方法来控制序列化逻辑,同时实现ReadJson处理反序列化(如果需要的话):

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

public class CarJsonConverter : JsonConverter<Car>
{
    public override void WriteJson(JsonWriter writer, Car value, JsonSerializer serializer)
    {
        // 创建JObject存储要序列化的属性
        var jObject = new JObject();
        
        // 序列化Car类的基础属性
        jObject.Add("Model", value.Model);
        jObject.Add("Year", value.Year);
        jObject.Add("Features", JToken.FromObject(value.Features, serializer));
        jObject.Add("CarId", value.CarId);
        jObject.Add("Id", value.Id);
        
        // 仅当Id不为0时,才序列化Car1属性
        if (value.Id != 0)
        {
            jObject.Add("Car1", JToken.FromObject(value.Car1, serializer));
        }
        
        // 将JObject写入JsonWriter
        jObject.WriteTo(writer);
    }

    public override Car ReadJson(JsonReader reader, Type objectType, Car existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // 反序列化逻辑,按需实现
        var jObject = JObject.Load(reader);
        var car = existingValue ?? new Car();
        
        car.Model = jObject["Model"]?.ToString();
        car.Year = jObject["Year"]?.ToObject<DateTime>() ?? default;
        car.Features = jObject["Features"]?.ToObject<List<string>>(serializer) ?? new List<string>();
        car.CarId = jObject["CarId"]?.ToObject<int>() ?? 0;
        
        // 仅当Id非0且Json中存在Car1属性时,才反序列化该属性
        if (car.Id != 0 && jObject.ContainsKey("Car1"))
        {
            car.Car1 = jObject["Car1"].ToObject<Car>(serializer);
        }
        
        return car;
    }
}

2. 使用自定义转换器

有两种方式可以应用这个转换器:

方式一:序列化时传入配置

var settings = new JsonSerializerSettings
{
    Converters = new List<JsonConverter> { new CarJsonConverter() }
};

string json = JsonConvert.SerializeObject(car, settings);

方式二:给Car类添加特性标记

直接在Car类上添加[JsonConverter]特性,这样每次序列化都会自动使用这个转换器:

[JsonConverter(typeof(CarJsonConverter))]
public class Car : Base1 {
    // 原类属性...
}

为什么之前的PreserveReferencesHandling无效?

因为你的Car1属性的getter逻辑是:如果_car为null就返回一个新的Car实例,而这个新实例的Id默认是0,会继续触发Car1的getter,形成无限循环。即使开启PreserveReferencesHandling.Objects,也无法阻止这种动态生成新对象导致的循环引用,所以必须通过自定义转换器手动控制该属性的序列化时机。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:47:19