.NET 6中基于System.Text.Json或Newtonsoft.JSON实现无特性依赖的自定义JSON序列化方案咨询
当然可以!不管是用Newtonsoft.Json(也就是大家常说的Json.NET)还是微软官方的System.Text.Json,都能通过配置它们的序列化扩展机制来实现你要的所有规则,而且完全不用在业务模型类上加任何特性,完美避免了业务代码和序列化器的耦合。下面分别给你两种方案的具体实现:
使用Newtonsoft.Json实现
Newtonsoft.Json的扩展性很强,我们可以通过自定义ContractResolver来实现所有规则,无需手动写大量反射递归代码:
1. 自定义ContractResolver(核心逻辑)
我们继承CamelCasePropertyNamesContractResolver(顺便实现驼峰命名,匹配你期望的输出格式),重写属性创建逻辑来处理所有空值规则:
public class IgnoreEmptyValuesContractResolver : CamelCasePropertyNamesContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); // 规则3:字符串为空或null时跳过该属性 if (property.PropertyType == typeof(string)) { property.ShouldSerialize = instance => { string value = (string)property.ValueProvider.GetValue(instance); return !string.IsNullOrEmpty(value); }; } // 规则4:空IEnumerable(包括空List)时跳过该属性 else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType) && property.PropertyType != typeof(string)) { property.ShouldSerialize = instance => { IEnumerable enumerable = (IEnumerable)property.ValueProvider.GetValue(instance); return enumerable != null && enumerable.GetEnumerator().MoveNext(); }; } // 规则1+2:嵌套对象为null,或仅含空/Null值时跳过该属性 else if (!property.PropertyType.IsValueType && property.PropertyType != typeof(string)) { property.ShouldSerialize = instance => { object value = property.ValueProvider.GetValue(instance); if (value == null) return false; // 处理null的嵌套对象 // 检查嵌套对象的所有属性是否都为空/Null var objectProperties = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); return objectProperties.Any(p => { var propValue = p.GetValue(value); if (propValue == null) return false; if (propValue is string str) return !string.IsNullOrEmpty(str); if (propValue is IEnumerable enumerable && !(propValue is string)) return enumerable.GetEnumerator().MoveNext(); // 值类型判断是否为默认值(可选,根据你的业务需求调整) return !EqualityComparer.Default.Equals(propValue, Activator.CreateInstance(p.PropertyType)); }); }; } return property; } }
2. 封装泛型序列化方法
把配置封装成独立的序列化类,业务代码只需要依赖这个类即可,完全隔离具体的序列化器:
public class MyNewtonsoftSerializer { private readonly JsonSerializerSettings _serializerSettings; public MyNewtonsoftSerializer() { _serializerSettings = new JsonSerializerSettings { ContractResolver = new IgnoreEmptyValuesContractResolver() // 可以添加其他全局配置,比如日期格式、缩进等 }; } public string Serialize<T>(T value) { return JsonConvert.SerializeObject(value, _serializerSettings); } // 可选:添加反序列化方法 public T Deserialize<T>(string json) { return JsonConvert.DeserializeObject<T>(json, _serializerSettings); } }
使用System.Text.Json实现
针对.NET 6,System.Text.Json也能通过自定义转换器实现需求,官方还提供了IgnoreEmptyCollections这类原生配置,简化代码:
1. 自定义转换器(处理空字符串和空嵌套对象)
首先实现一个字符串转换器,跳过空字符串:
public class IgnoreEmptyStringConverter : JsonConverter<string> { public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.GetString() ?? string.Empty; } public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) { // 空字符串时不写入该属性 if (!string.IsNullOrEmpty(value)) { writer.WriteStringValue(value); } } }
然后实现通用对象转换器,处理仅含空值的嵌套对象:
public class IgnoreEmptyObjectConverter : JsonConverter<object> { public override bool CanConvert(Type typeToConvert) { // 只处理非值类型、非字符串、非集合的引用类型 return !typeToConvert.IsValueType && typeToConvert != typeof(string) && !typeof(IEnumerable).IsAssignableFrom(typeToConvert); } public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return JsonSerializer.Deserialize(ref reader, typeToConvert, options); } public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) { // 检查嵌套对象是否有非空属性 var properties = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); bool hasNonEmptyValue = false; foreach (var prop in properties) { var propValue = prop.GetValue(value); if (propValue == null) continue; if (propValue is string str && !string.IsNullOrEmpty(str)) { hasNonEmptyValue = true; break; } if (propValue is IEnumerable enumerable && !(propValue is string)) { if (enumerable.GetEnumerator().MoveNext()) { hasNonEmptyValue = true; break; } } // 值类型判断是否为默认值 else if (!EqualityComparer.Default.Equals(propValue, Activator.CreateInstance(prop.PropertyType))) { hasNonEmptyValue = true; break; } } // 只有存在非空值时才序列化该嵌套对象 if (hasNonEmptyValue) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } } }
2. 封装泛型序列化方法
配置序列化选项并封装成独立类:
public class MySystemTextJsonSerializer { private readonly JsonSerializerOptions _serializerOptions; public MySystemTextJsonSerializer() { _serializerOptions = new JsonSerializerOptions { // 规则1:跳过null属性 DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, // 规则4:跳过空集合(.NET 6+原生支持) IgnoreEmptyCollections = true, // 驼峰命名,匹配期望输出 PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; // 添加自定义转换器 _serializerOptions.Converters.Add(new IgnoreEmptyStringConverter()); _serializerOptions.Converters.Add(new IgnoreEmptyObjectConverter()); } public string Serialize<T>(T value) { return JsonSerializer.Serialize(value, _serializerOptions); } // 可选:添加反序列化方法 public T Deserialize<T>(string json) { return JsonSerializer.Deserialize<T>(json, _serializerOptions); } }
测试验证
用你提供的测试实例调用任意一个序列化类的Serialize方法,都会得到你期望的结果:
{"name":"My Name"}
两种方案都完全符合你的要求:业务模型无需添加任何特性,泛型方法支持任意类型,核心逻辑都是基于序列化库的扩展机制实现,没有手动写大量反射递归代码。
内容的提问来源于stack exchange,提问作者dzenesiz
相关产品推荐
相关产品推荐

