如何一次性抑制CS9035规则?Required属性类配置绑定报错处理
问题场景
定义了带有required关键字的配置类:
public class Options { [Required] public required string Endpoint { get; set; } }
尝试通过手动实例化后调用Bind加载配置时,触发编译器错误:
Error CS9035: Required member 'Options.Endpoint' must be set in the object initializer or attribute constructor.
手动初始化Endpoint = null!的方式不够优雅,以下是更合理的解决方案:
解决方案
1. 采用.NET官方Options绑定机制(推荐)
直接使用框架提供的Configure或Bind扩展方法,无需手动实例化对象,框架会自动处理required成员的初始化,同时支持配置验证:
public static IServiceCollection AddOptions(this IServiceCollection services, IConfigurationSection section) { // 绑定配置并注册Options实例,同时启用数据注解验证 services.AddOptions<Options>() .Bind(section) .ValidateDataAnnotations(); return services; }
这种方式完全符合.NET配置最佳实践,无需绕开编译器检查,还能集成验证逻辑。
2. 给无参构造函数添加[SetsRequiredMembers]特性
在配置类的无参构造函数上标记[SetsRequiredMembers],告知编译器该构造函数会确保后续代码初始化所有required成员,从而跳过编译检查:
using System.Diagnostics.CodeAnalysis; // 需引入此命名空间 public class Options { [SetsRequiredMembers] public Options() { } [Required] public required string Endpoint { get; set; } }
修改后即可正常使用new Options(),后续通过section.Bind(options)赋值即可。
3. 用反射创建实例
通过Activator.CreateInstance<T>绕开编译器的required成员检查,适合必须手动实例化的场景:
public static IServiceCollection AddOptions(this IServiceCollection services, IConfigurationSection section) { var options = Activator.CreateInstance<Options>(); section.Bind(options); // 后续验证或注册逻辑... return services; }
注意:反射会将required成员设为类型默认值(如string为null),需确保后续Bind和验证逻辑能覆盖并校验这些值。
4. 改用构造函数初始化required成员
将required成员移至构造函数参数,通过配置值直接传入初始化,同时可将属性设为只读保证不可变性:
public class Options { [Required] public string Endpoint { get; } public Options(string endpoint) { Endpoint = endpoint; } }
对应的扩展方法实现:
public static IServiceCollection AddOptions(this IServiceCollection services, IConfigurationSection section) { var endpoint = section["Endpoint"] ?? throw new InvalidOperationException("缺少Endpoint配置项"); var options = new Options(endpoint); services.AddSingleton(options); return services; }
这种方式从根源上避免了required关键字的编译检查问题,同时增强了配置类的不可变性。
内容的提问来源于stack exchange,提问作者Jack Miller

