Newtonsoft JSON:如何依据另一个属性值忽略指定属性?
解决方案:基于关联布尔属性动态忽略JSON序列化属性
完全可以实现,不用手动将复杂子类设为null。你可以通过自定义特性+自定义ContractResolver的组合来实现这个需求,步骤如下:
1. 定义自定义特性
先创建一个特性,用来标记当前属性需要被哪个布尔属性控制是否序列化:
[AttributeUsage(AttributeTargets.Property)] public class IgnoreWhenBooleanFalseAttribute : Attribute { public string BooleanPropertyName { get; } public IgnoreWhenBooleanFalseAttribute(string booleanPropertyName) { BooleanPropertyName = booleanPropertyName; } }
2. 实现自定义ContractResolver
继承DefaultContractResolver,重写CreateProperty方法,根据自定义特性的规则动态决定是否序列化目标属性:
public class ConditionalIgnoreContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); // 检查当前属性是否带有自定义忽略特性 var ignoreAttribute = member.GetCustomAttribute<IgnoreWhenBooleanFalseAttribute>(); if (ignoreAttribute != null) { // 获取控制序列化的布尔属性 var booleanProperty = member.DeclaringType.GetProperty(ignoreAttribute.BooleanPropertyName); if (booleanProperty != null && booleanProperty.PropertyType == typeof(bool)) { // 动态设置ShouldSerialize逻辑 property.ShouldSerialize = instance => { bool booleanValue = (bool)booleanProperty.GetValue(instance); // 只有当布尔属性为true时才序列化当前属性 return booleanValue; }; } } return property; } }
3. 在数据类中使用特性
把自定义特性标记在需要被控制的复杂子类属性上,指定对应的布尔属性名称:
public class ComplexDataClass { // 控制开关 public bool UseComplexSubclass { get; set; } // 当UseComplexSubclass为false时,该属性不会被序列化 [IgnoreWhenBooleanFalse(nameof(UseComplexSubclass))] public ComplexSubclass SubclassData { get; set; } // 其他属性... } public class ComplexSubclass { // 大量占用空间的属性... public string LargeData1 { get; set; } public string LargeData2 { get; set; } // ... }
4. 序列化时使用自定义ContractResolver
在序列化配置中指定我们的自定义解析器,无需手动设置SubclassData为null:
var settings = new JsonSerializerSettings { ContractResolver = new ConditionalIgnoreContractResolver(), // 可选:保留NullValueHandling.Ignore,避免其他null属性被序列化 NullValueHandling = NullValueHandling.Ignore }; var data = new ComplexDataClass { UseComplexSubclass = false, SubclassData = new ComplexSubclass { LargeData1 = "xxx", LargeData2 = "yyy" } }; string json = JsonConvert.SerializeObject(data, settings); // 序列化结果中不会包含SubclassData属性
补充说明
- 这种方式无需修改原有业务逻辑,所有控制逻辑都集中在特性和解析器中,扩展性强
- 如果需要多个布尔属性控制,或者更复杂的逻辑,可以扩展自定义特性的参数和ContractResolver的判断逻辑
- 如果你使用的是System.Text.Json而非Newtonsoft.Json,思路类似,需要自定义
JsonConverter或者JsonTypeInfo来实现条件序列化
内容的提问来源于stack exchange,提问作者Marcel Grüger
相关产品推荐
相关产品推荐

