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

如何使用System.Text.Json对嵌套类进行条件序列化

如何使用System.Text.Json对嵌套类进行条件序列化

我来帮你搞定这个嵌套类的条件序列化需求!你的核心目标应该是:根据MyPoco实例的IgnoreCustomValue开关,决定是否跳过嵌套类MyLittlePoco中值为//的属性——当开关为true时,不序列化值等于//的属性;开关为false时,所有属性都正常序列化。

下面给你两种可行的实现方案,你可以根据自己的场景选择:


方案一:自定义JsonConverter(推荐,无需修改原类结构)

这种方式不需要改动你现有的MyPoco和MyLittlePoco类,通过自定义转换器直接控制序列化逻辑,能精准访问到每个MyPoco实例的开关状态:

using System.Text.Json;
using System.Text.Json.Serialization;

// 你的原类保持不变
public class MyPoco
{
    [JsonIgnore]
    public bool IgnoreCustomValue { get; set; }

    public MyLittlePoco LPoco { get; set; }
}

public class MyLittlePoco
{
    public string DataOne { get; set; }
    public string DataTwo { get; set; }
}

// 自定义转换器处理MyPoco的序列化
public class MyPocoConverter : JsonConverter<MyPoco>
{
    // 反序列化逻辑(如果不需要自定义,用默认实现即可)
    public override MyPoco Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return JsonSerializer.Deserialize<MyPoco>(ref reader, options);
    }

    // 核心:自定义序列化逻辑
    public override void Write(Utf8JsonWriter writer, MyPoco value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();

        // 处理嵌套的LPoco属性
        if (value.LPoco != null)
        {
            writer.WriteStartObject(nameof(MyPoco.LPoco));

            // 根据IgnoreCustomValue开关决定是否跳过值为//的属性
            if (!value.IgnoreCustomValue || value.LPoco.DataOne != "//")
            {
                writer.WriteString(nameof(MyLittlePoco.DataOne), value.LPoco.DataOne);
            }

            if (!value.IgnoreCustomValue || value.LPoco.DataTwo != "//")
            {
                writer.WriteString(nameof(MyLittlePoco.DataTwo), value.LPoco.DataTwo);
            }

            writer.WriteEndObject();
        }

        writer.WriteEndObject();
    }
}

// 使用示例
var options = new JsonSerializerOptions
{
    Converters = { new MyPocoConverter() },
    WriteIndented = true // 可选:格式化输出JSON,方便查看
};

// 测试开关为true的情况
var pocoWithIgnore = new MyPoco
{
    IgnoreCustomValue = true,
    LPoco = new MyLittlePoco { DataOne = "//", DataTwo = "Hola" }
};
string jsonWithIgnore = JsonSerializer.Serialize(pocoWithIgnore, options);
// 输出结果会跳过DataOne:
// {
//   "LPoco": {
//     "DataTwo": "Hola"
//   }
// }

// 测试开关为false的情况
var pocoWithoutIgnore = new MyPoco
{
    IgnoreCustomValue = false,
    LPoco = new MyLittlePoco { DataOne = "//", DataTwo = "Hola" }
};
string jsonWithoutIgnore = JsonSerializer.Serialize(pocoWithoutIgnore, options);
// 输出结果会包含所有属性:
// {
//   "LPoco": {
//     "DataOne": "//",
//     "DataTwo": "Hola"
//   }
// }

方案二:使用TypeInfoResolver修饰符(适合通用场景)

如果你需要对多个类应用类似的条件序列化规则,可以用DefaultJsonTypeInfoResolver的修饰符来实现。不过要注意:这种方式下,嵌套类无法直接访问外层类的开关属性,所以我们需要把开关改为全局选项(如果每个实例需要独立开关,方案一更合适):

using System.Text.Json;
using System.Text.Json.Serialization;

// 自定义全局选项类
public class CustomSerializationOptions
{
    public bool IgnoreCustomValue { get; set; }
}

// 你的原类保持不变
public class MyPoco
{
    public MyLittlePoco LPoco { get; set; }
}

public class MyLittlePoco
{
    public string DataOne { get; set; }
    public string DataTwo { get; set; }
}

// 类型信息修饰符:添加条件序列化规则
public static void IgnoreCustomValueModifier(JsonTypeInfo typeInfo)
{
    // 只处理MyLittlePoco类型
    if (typeInfo.Type != typeof(MyLittlePoco))
        return;

    foreach (JsonPropertyInfo property in typeInfo.Properties)
    {
        property.ShouldSerialize = (obj, value) =>
        {
            // 从JsonSerializerOptions中获取全局开关
            if (typeInfo.Options.ExtensionData.TryGetValue(nameof(CustomSerializationOptions), out var optObj) 
                && optObj is CustomSerializationOptions options)
            {
                // 如果开关为false,序列化所有属性;如果为true,跳过值为//的属性
                return !options.IgnoreCustomValue || value?.ToString() != "//";
            }
            // 默认序列化所有属性
            return true;
        };
    }
}

// 使用示例
var globalOptions = new CustomSerializationOptions { IgnoreCustomValue = true };
var jsonOptions = new JsonSerializerOptions
{
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { IgnoreCustomValueModifier }
    },
    // 将全局选项存入扩展数据中
    ExtensionData = new Dictionary<string, object> { { nameof(CustomSerializationOptions), globalOptions } },
    WriteIndented = true
};

var poco = new MyPoco
{
    LPoco = new MyLittlePoco { DataOne = "//", DataTwo = "Hola" }
};
string json = JsonSerializer.Serialize(poco, jsonOptions);
// 输出结果会跳过DataOne:
// {
//   "LPoco": {
//     "DataTwo": "Hola"
//   }
// }

总结

  • 如果你需要每个MyPoco实例独立控制开关,优先选择方案一的自定义转换器,逻辑更直接,也不需要改动原类。
  • 如果需要对多个类应用统一的条件序列化规则,可以用方案二的类型修饰符,适合通用场景。

备注:内容来源于stack exchange,提问作者KrumpiDumpi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 15:52:56