如何在System.Text.Json序列化时按场景指定包含或排除的类属性
System.Text.Json 动态选择序列化属性的实现方案
System.Text.Json 原生提供了等价于 Newtonsoft 中 ContractResolver 的能力,不需要引入额外的序列化库,根据你使用的 .NET 版本可以选择以下两种实现方案:
方案1:.NET 7+ 自定义 JsonTypeInfoResolver(推荐)
.NET 7 开始官方提供了 DefaultJsonTypeInfoResolver 用来修改序列化元数据,你可以为不同场景自定义过滤规则,生成独立的序列化配置,互不干扰。
通用过滤扩展方法示例:
using System.Text.Json; using System.Text.Json.Serialization.Metadata; public static class JsonSerializationExtensions { // 按属性名列表排除指定属性,生成对应序列化配置 public static JsonSerializerOptions CreateExcludedOptions<T>(params string[] excludedProperties) { var options = new JsonSerializerOptions { // 可按需配置其他规则,比如驼峰命名 PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; var resolver = new DefaultJsonTypeInfoResolver(); resolver.Modifiers.Add(typeInfo => { if (typeInfo.Type != typeof(T)) return; // 移除需要排除的属性 foreach (var prop in typeInfo.Properties.ToList()) { if (excludedProperties.Contains(prop.Name, StringComparer.OrdinalIgnoreCase)) { typeInfo.Properties.Remove(prop); } } }); options.TypeInfoResolver = resolver; return options; } }
使用示例:
public class Foo { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } } var foo = new Foo { Name = "测试", Age = 20, Address = "北京市" }; // 场景A:包含所有属性,直接序列化 var jsonA = JsonSerializer.Serialize(foo); // 场景B:排除Name属性,使用自定义配置 var optionsB = JsonSerializationExtensions.CreateExcludedOptions<Foo>("Name"); var jsonB = JsonSerializer.Serialize(foo, optionsB);
方案2:兼容 .NET 6 及更低版本的实现
如果你的项目还在使用 .NET 6 或更早版本,可以通过自定义 JsonConverter 实现动态过滤:
public class DynamicPropertyConverter<T> : JsonConverter<T> { private readonly HashSet<string> _excludedProps; public DynamicPropertyConverter(params string[] excludedProps) { _excludedProps = new HashSet<string>(excludedProps, StringComparer.OrdinalIgnoreCase); } public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 反序列化逻辑可按需实现,这里直接使用默认反序列化 return JsonSerializer.Deserialize<T>(ref reader, options); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { writer.WriteStartObject(); foreach (var prop in typeof(T).GetProperties()) { if (_excludedProps.Contains(prop.Name)) continue; var propValue = prop.GetValue(value); writer.WritePropertyName(options.PropertyNamingPolicy?.ConvertName(prop.Name) ?? prop.Name); JsonSerializer.Serialize(writer, propValue, prop.PropertyType, options); } writer.WriteEndObject(); } }
使用示例:
var optionsB = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new DynamicPropertyConverter<Foo>("Name") } }; var jsonB = JsonSerializer.Serialize(foo, optionsB);
注意事项
- 如果需要按包含逻辑指定属性,只需要把上述代码的排除判断改为包含判断,仅保留指定属性即可。
- 方案2的自定义Converter适合简单平面对象场景,复杂嵌套对象、字段序列化的场景建议升级到.NET 7+使用TypeInfoResolver方案,避免重复处理序列化边缘逻辑。
内容的提问来源于stack exchange,提问作者Hugo
相关产品推荐
相关产品推荐

