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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:24:07