C# 10及更早版本中替代C# 11 required修饰符的方案
C# 10及更早版本替代
required修饰符的方案 C# 11的required修饰符能在编译时强制字段/属性必须被初始化,在更早版本里,我们可以通过以下几种方案实现类似效果:
1. 仅提供带必填参数的构造函数(编译时检查)
这是最直接的编译时强制方案:不定义无参构造函数,只提供包含所有必填属性对应参数的构造函数。这样创建类实例时,必须通过构造函数传入所有必填值,无法通过对象初始化器漏掉必填项。
示例代码:
public class User { public string Name { get; } public int Age { get; } // 仅提供带必填参数的构造函数,无无参构造 public User(string name, int age) { Name = name ?? throw new ArgumentNullException(nameof(name)); Age = age > 0 ? age : throw new ArgumentOutOfRangeException(nameof(age)); } }
这种方式的优势是完全在编译阶段阻止未初始化必填项的情况,和required的编译时检查效果一致。
2. 结合私有setter/init-only属性与构造函数(C# 9+支持init)
如果需要保留对象初始化器的使用方式,同时确保必填属性被初始化,可以将属性设为init(C# 9引入)或私有setter,同时提供包含必填参数的构造函数,或者在构造逻辑中添加运行时检查:
示例(C# 9+使用init):
public class User { public string Name { get; init; } = null!; public int Age { get; init; } // 支持通过构造函数初始化 public User(string name, int age) { Name = name; Age = age; } // 允许对象初始化器,但需运行时检查必填项 public User() { if (string.IsNullOrEmpty(Name)) throw new InvalidOperationException("Name必须被初始化"); if (Age <= 0) throw new InvalidOperationException("Age必须设置为有效数值"); } }
注:这种方式下,编译器不会强制对象初始化器设置必填属性,依赖运行时检查确保有效性。
3. 自定义代码分析器(编译时检查)
如果需要完全模拟required的编译时强制对象初始化器设置属性的行为,可以编写自定义Roslyn代码分析器,或者使用现有分析器库(如StyleCop)配置规则,强制要求创建实例时必须初始化指定属性。这种方式能在编译阶段给出警告或错误,和required的体验最接近,但需要额外的开发或配置工作。
4. 运行时验证(属性setter检查)
对于不需要编译时检查,只需要运行时确保必填项的场景,可以在属性的setter或getter中添加检查,确保属性被赋值为有效内容:
public class User { private string? _name; public string Name { get => _name ?? throw new InvalidOperationException("Name未初始化"); set => _name = value ?? throw new ArgumentNullException(nameof(value)); } public int Age { get; set; } }
这种方式在使用对象初始化器时,如果漏掉Name,第一次访问该属性时会抛出异常,属于运行时检查。
内容的提问来源于stack exchange,提问作者bahrep
相关产品推荐
相关产品推荐

