如何让System.Text.Json忽略带有required修饰符的属性
嘿,我完全懂你这个糟心的问题——明明给带required修饰符的属性加了[JsonIgnore],结果System.Text.Json还是报错炸锅,就因为它揪着“required属性没有setter”不放,可你根本不需要反序列化这个类型啊!
其实问题出在System.Text.Json的元数据构建逻辑上:只要属性标了C#的required修饰符,编译器会自动给它加上[RequiredMember]特性,而序列化器看到这个特性,就默认认为这个属性需要参与反序列化,哪怕你加了[JsonIgnore],它还是会去检查这个属性有没有setter/init方法,直接触发那个讨厌的InvalidOperationException。
下面给你几个实用的解决方案,按需选就行:
方法1:精准移除单个属性的序列化元数据(保留属性上的required)
如果你就想保留属性上的required修饰符,那可以通过自定义序列化配置,在元数据构建时直接把这个属性从序列化器的处理列表里删掉,这样它就不会触发required检查了:
// 创建序列化选项 var options = new JsonSerializerOptions(); // 自定义类型元数据的修改逻辑 options.TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { // 只处理你的目标类型 if (typeInfo.Type == typeof(Example)) { // 找到要忽略的那个属性 var unwantedProp = typeInfo.Properties .FirstOrDefault(p => p.Name == nameof(Example.RequiredButDontSerialize)); if (unwantedProp != null) { // 从元数据里移除它 typeInfo.Properties.Remove(unwantedProp); } } } } }; // 用这个配置序列化就没问题了 var jsonString = JsonSerializer.Serialize(yourExampleInstance, options);
方法2:用构造函数参数实现required约束(更简洁)
如果可以接受调整一下required的实现方式,其实换个思路更简单:把required修饰符从属性上移到构造函数参数上,这样既保证了对象创建时必须传入这个值,又不会让序列化器盯上这个属性:
public class Example { // 把required约束放在构造函数参数上 public Example(string requiredButDontSerialize) { RequiredButDontSerialize = requiredButDontSerialize; } [JsonIgnore] public string RequiredButDontSerialize { get; init; } public string AnotherPropertyWhatever { get; init; } }
这样一来,C#编译器依然会强制你创建Example实例时必须传入requiredButDontSerialize的值,而System.Text.Json因为属性上没有required修饰符,加上你已经加了[JsonIgnore],完全不会再管这个属性,自然就不会报错了。
补充:全局忽略所有required成员检查(不推荐,除非你确实需要)
如果你有一堆这样的属性,或者不在乎全局禁用required检查,也可以直接设置序列化选项的IgnoreRequiredMembers为true,不过这个是全局生效的,会忽略所有类型的required成员检查,用的时候要谨慎:
var options = new JsonSerializerOptions { IgnoreRequiredMembers = true };
内容来源于stack exchange

