required 修饰符(C# 参考)

required 修饰符表示它所应用的字段或属性必须由对象初始值设定项进行初始化。 用于初始化该类型新实例的任何表达式都必须初始化所有必需的成员。 required 修饰符从 C# 11 开始可用。 required 修饰符使开发人员能够创建必须正确初始化属性或字段的类型,但仍允许使用对象初始值设定项进行初始化。 多个规则可确保此行为:

  • required 修饰符可应用于在 struct 中声明的字段和属性,以及 class 类型,包括 recordrecord struct 类型。 required 修饰符不能应用于 interface 的成员。
  • 显式接口实现不能标记为 required。 不能在对象初始值设定项中设置它们。
  • 必须初始化必需的成员,但可将其初始化为 null。 如果该类型是不可为 null 的引用类型,则在将成员初始化为 null 时编译器会发出警告。 如果成员根本没有初始化,编译器会发出错误。
  • 必需的成员必须至少与其包含类型一样可见。 例如,public 类不能包含 protectedrequired 字段。 此外,必需的属性必须具有至少与其包含类型一样可见的资源库(setinit 访问器)。 不可访问的成员不能由创建实例的代码设置。
  • 派生类不能隐藏在基类中声明的 required 成员。 隐藏必需的成员可防止调用方为其使用对象初始值设定项。 此外,重写必需属性的派生类型必须包含 required 修饰符。 派生类型无法删除 required 状态。 派生类型可以在重写属性时添加 required 修饰符。
  • 当类型参数包含 new() 约束时,不能将具有任何 required 成员的类型用作类型参数。 编译器无法强制在泛型代码中初始化所有必需的成员。
  • 不允许对记录上的位置参数声明使用 required 修饰符。 可以为包含 required 修饰符的位置属性添加显式声明。

某些类型(如位置记录)使用主构造函数初始化位置属性。 如果其中任一属性包括 required 修饰符,则主构造函数将添加 SetsRequiredMembers 属性。 这表示主构造函数初始化所有必需的成员。 可以使用 System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute 特性编写自己的构造函数。 但是,编译器不会验证这些构造函数是否初始化所有必需的成员。 该特性会转而向编译器断言构造函数会初始化所有必需的成员。 SetsRequiredMembers 特性会将这些规则添加到构造函数:

  • 链接到另一个使用 SetsRequiredMembers 属性批注的构造函数(this()base())的构造函数还必须包含 SetsRequiredMembers 属性。 这可确保调用方能够正确使用所有适当的构造函数。
  • 如果任何成员为 required,则为 record 类型生成的复制构造函数应用 SetsRequiredMembers 属性。

警告

SetsRequiredMembers 禁用编译器检查所有 required 成员在创建对象时是否已初始化。 请谨慎使用。

下面的代码显示了对 FirstNameLastName 属性使用 required 修饰符的类层次结构:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName) =>
        (FirstName, LastName) = (firstName, lastName);

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    public int? Age { get; set; }
}

public class Student : Person
{
    public Student() : base()
    {
    }

    [SetsRequiredMembers]
    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
    }

    public double GPA { get; set; }
}

有关所需成员的详细信息,请参阅 C#11 - 必需成员功能规范。