使用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
相关产品推荐
相关产品推荐

