如何使用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
相关产品推荐
相关产品推荐

