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

使用System.Text.Json根据另一属性值动态忽略序列化对象属性

实现方案

我们可以通过「自定义特性 + System.Text.Json 序列化配置」实现需求,以下为完整实现步骤:


1. 定义条件包含特性

首先创建用于标记属性的自定义特性,存储判断序列化所需的参数:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class IncludeIfListIncludesAttribute : Attribute
{
    /// <summary>
    /// 用于判断的列表属性名称
    /// </summary>
    public string ListPropertyName { get; }
    /// <summary>
    /// 序列化当前属性要求列表必须包含的值
    /// </summary>
    public string RequiredValue { get; }

    public IncludeIfListIncludesAttribute(string listPropertyName, string requiredValue)
    {
        ListPropertyName = listPropertyName;
        RequiredValue = requiredValue;
    }
}

注:这里调整了示例中的参数形式,改为传入属性名称字符串,搭配nameof语法使用既安全又便于反射读取属性值。


2. 实现动态属性过滤逻辑

如果你使用的是 System.Text.Json 7.0及以上版本,可以通过JsonTypeInfo修改器实现全局通用的属性过滤逻辑,不需要为每个业务类单独写转换器:

public static void ConditionalSerializeFilter(JsonTypeInfo typeInfo)
{
    // 仅处理类类型的序列化
    if (typeInfo.Kind != JsonTypeInfoKind.Object) return;

    foreach (var jsonProperty in typeInfo.Properties)
    {
        // 读取属性上的自定义特性
        var includeAttr = jsonProperty.AttributeProvider?
            .GetCustomAttributes(typeof(IncludeIfListIncludesAttribute), false)
            .Cast<IncludeIfListIncludesAttribute>()
            .FirstOrDefault();
        if (includeAttr == null) continue;

        // 绑定序列化判断逻辑
        jsonProperty.ShouldSerialize = (instance, propertyValue) =>
        {
            // 反射获取列表属性值
            var listProp = instance.GetType().GetProperty(includeAttr.ListPropertyName);
            if (listProp?.GetValue(instance) is not IEnumerable<string> listValue)
                return false; // 列表为空默认不序列化当前属性

            // 判断是否满足序列化条件
            return listValue.Contains(includeAttr.RequiredValue);
        };
    }
}

3. 配置序列化参数并测试

修改你的业务类添加特性标记,然后配置序列化参数即可使用:

// 业务类添加特性标记
public class MyClass
{
    public List<string> Types { get; set; }

    [IncludeIfListIncludes(nameof(Types), "Type1")]
    public string PropertyValidForType1 {get; set;}

    [IncludeIfListIncludes(nameof(Types), "Type2")]
    public string PropertyValidForType2 {get; set;}

    [IncludeIfListIncludes(nameof(Types), "Type3")]
    public string PropertyValidForType3 {get; set;}
}

// 序列化调用
var serializeOptions = new JsonSerializerOptions
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { ConditionalSerializeFilter }
    },
    WriteIndented = true // 可选:格式化输出方便查看
};

var c = new MyClass
{
    Types = new List<string> { "Type1", "Type3" },
    PropertyValidForType1 = "A",
    PropertyValidForType2 = "B",
    PropertyValidForType3 = "C",
};

var jsonString = JsonSerializer.Serialize(c, serializeOptions);
Console.WriteLine(jsonString);

输出结果

{
  "Types": [
    "Type1",
    "Type3"
  ],
  "PropertyValidForType1": "A",
  "PropertyValidForType3": "C"
}

低版本兼容方案(System.Text.Json <7.0)

如果使用的是低于7.0的版本,可以为业务类实现自定义转换器:

public class MyClassJsonConverter : JsonConverter<MyClass>
{
    public override MyClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 按需实现反序列化逻辑
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        // 写入固定的Types属性
        writer.WritePropertyName(nameof(MyClass.Types));
        JsonSerializer.Serialize(writer, value.Types, options);

        // 遍历其他属性判断是否需要序列化
        var properties = typeof(MyClass).GetProperties().Where(p => p.Name != nameof(MyClass.Types));
        foreach (var prop in properties)
        {
            var attr = prop.GetCustomAttribute<IncludeIfListIncludesAttribute>();
            if (attr == null || (value.Types != null && value.Types.Contains(attr.RequiredValue)))
            {
                writer.WritePropertyName(prop.Name);
                JsonSerializer.Serialize(writer, prop.GetValue(value), prop.PropertyType, options);
            }
        }
        writer.WriteEndObject();
    }
}

使用时把转换器加入序列化配置即可:

var options = new JsonSerializerOptions
{
    Converters = { new MyClassJsonConverter() },
    WriteIndented = true
};

内容的提问来源于stack exchange,提问作者Kevin Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 23:21:03