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

从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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:06:03