Newtonsoft.Json如何根据属性条件实现差异化序列化
实现方案
这个需求用自定义JsonConverter即可实现,你之前写的转换器逻辑不生效,核心原因是泛型JsonConverter<T>的WriteJson是抽象方法没有默认实现,只要处理好多态序列化时的转换器递归问题,就能完全匹配需求,不需要复杂的ContractResolver配置。
完整自定义转换器实现
public class IndividualJsonConverter : JsonConverter<Individual> { // 本方案仅实现序列化逻辑,需要反序列化可自行扩展ReadJson方法 public override Individual ReadJson(JsonReader reader, Type objectType, Individual existingValue, bool hasExistingValue, JsonSerializer serializer) { throw new NotImplementedException(); } public override void WriteJson(JsonWriter writer, Individual value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } // 非哺乳动物分支:直接写入Name字符串 if (!value.IsMammal) { writer.WriteValue(value.Name); return; } // 哺乳动物分支:临时移除当前转换器,避免递归触发当前转换器导致栈溢出 var currentConverter = this; serializer.Converters.Remove(currentConverter); try { // 传入实例的实际运行时类型,确保派生类(比如Human)的所有属性都能被正常序列化 serializer.Serialize(writer, value, value.GetType()); } finally { // 还原转换器配置,不影响后续其他对象的序列化 serializer.Converters.Add(currentConverter); } } }
使用方式
序列化时将转换器加入JsonSerializerSettings即可:
var habitat = new Habitat { Inhabitants = new List<Individual> { new Human { Name = "Frank" }, new Eagle { Name = "Brucie" } } }; var jsonSettings = new JsonSerializerSettings { Converters = { new IndividualJsonConverter() }, Formatting = Formatting.Indented }; string result = JsonConvert.SerializeObject(habitat, jsonSettings);
运行后输出的JSON结构和预期完全一致:Inhabitants数组中Human实例会被序列化为包含所有属性的对象,Eagle实例会直接输出为字符串"Brucie"。
注意点
- 调用
serializer.Serialize时必须传入实例的实际运行时类型value.GetType(),如果直接传入基类typeof(Individual),序列化器无法识别派生类的自定义属性,会导致属性丢失。 - 用try-finally块还原转换器配置是必要操作,否则同一个序列化器实例后续处理其他Individual类型对象时会丢失自定义转换逻辑。
内容的提问来源于stack exchange,提问作者Wouter Vandenputte
相关产品推荐
相关产品推荐

