从Newtonsoft.Json迁移到System.Text.Json的自定义序列化跳过规则咨询
System.Text.Json 自定义序列化规则实现方案
本方案适用于 System.Text.Json 7.0 及以上版本,通过自定义 JsonTypeInfoResolver 实现需要的规则,具体实现如下:
步骤1:配置基础序列化选项
首先开启原生支持的 null 值忽略规则,同时注册自定义类型解析器:
using System.Text.Json; using System.Text.Json.Serialization.Metadata; using System.ComponentModel; var options = new JsonSerializerOptions { // 原生支持规则2:属性值为null时跳过序列化 DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, // 注册自定义的类型解析器 TypeInfoResolver = new CustomJsonResolver(), WriteIndented = true };
步骤2:实现自定义类型解析器
通过自定义 IJsonTypeInfoResolver 实现另外两个规则:过滤带[ReadOnly]标记的属性、过滤序列化后为空对象的属性:
public class CustomJsonResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var typeInfo = base.GetTypeInfo(type, options); if (typeInfo.Kind != JsonTypeInfoKind.Object) return typeInfo; // 遍历所有可序列化属性,处理规则1 foreach (var property in typeInfo.Properties.ToList()) { // 检查属性是否标记了[ReadOnly] var readOnlyAttr = property.AttributeProvider?.GetCustomAttributes(typeof(ReadOnlyAttribute), true) .Cast<ReadOnlyAttribute>() .FirstOrDefault(); if (readOnlyAttr != null && readOnlyAttr.IsReadOnly) { // 移除带ReadOnly标记的属性,跳过序列化 typeInfo.Properties.Remove(property); continue; } // 处理规则3:属性值序列化后为空对象时跳过 var propertyType = property.PropertyType; // 仅处理引用类型和可空值类型,值类型本身不会是空对象 if (propertyType.IsValueType && Nullable.GetUnderlyingType(propertyType) == null) continue; property.ShouldSerialize = (_, obj) => { if (obj == null) return false; // null场景已被原生规则处理,此处兜底 // 检查当前属性值对应的类型,序列化后是否为空对象 return !IsEmptyObject(obj, options); }; } return typeInfo; } // 辅助方法:递归判断对象序列化后是否为空对象(无任何可序列化属性) private static bool IsEmptyObject(object obj, JsonSerializerOptions options) { var objType = obj.GetType(); var objTypeInfo = options.GetTypeInfo(objType); if (objTypeInfo.Kind != JsonTypeInfoKind.Object) return false; // 遍历该对象所有可序列化属性,判断是否有可输出的属性 foreach (var prop in objTypeInfo.Properties) { var propValue = prop.Get?.Invoke(obj); // 只要有一个属性满足序列化条件,就不是空对象 if (propValue != null && !IsEmptyObject(propValue, options)) { return false; } } // 所有属性都不可序列化,判定为空对象 return true; } }
步骤3:测试序列化效果
使用示例类进行测试:
var testCar = new Car { Id = "1234", Name = "Skoda", Owner = new Person { Id = "abcd", Name = null } }; var json = JsonSerializer.Serialize(testCar, options); Console.WriteLine(json);
输出结果完全符合预期:
{ "Name": "Skoda" }
兼容说明
如果使用的是System.Text.Json 6.x及更低版本,没有DefaultJsonTypeInfoResolver API,可以通过自定义JsonConverter实现相同逻辑,核心判断逻辑完全一致。
内容的提问来源于stack exchange,提问作者Thorberg
相关产品推荐
相关产品推荐

