required 修饰符(C# 参考)

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

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

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

  • 链接到使用 SetsRequiredMembers 属性注释的另一个构造函数的构造函数(this()base())还必须包含 SetsRequiredMembers 属性。 这可确保调用方能够正确使用所有适当的构造函数。
  • 对于 record 类型,如果其任何成员为 required,生成的复制构造函数将应用 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 - 必需成员 功能规范。