切换导航
简历
工具
演示
查询
导航菜单
服务端
30
前端
114
数据库
82
进阶开发
8
桌面程序
2
QA
15
软件使用
36
规范协议
5
操作系统
11
AI
0
复用资源
6
硬件
0
标签
C# 基础
Mybatis
ADO.NET
ASP.NET
Python 基础
Linq
Web Forms
.NET
Spring
SpringBoot
SpringCloud
.NET Core 中间件
Maven
.NET 类库
ASP.NET MVC
EF
NHibernate
WebApi
Java
外部链接
.NET Core SDK和运行时安装包
淘宝 NPM 镜像
查询网
Tables Generator线上表格转换工具
引用cdn在线脚本和样式
首页
服务端
C# 修饰符 required 介绍与使用
[TOC] ## 1. 必须修饰符 required required 修饰符表示它所应用的字段或属性必须由`对象初始值设定项`进行初始化。 用于初始化该类型新实例的任何表达式都必须初始化所有必需的成员。 required 修饰符从 C# 11 开始可用。 required 修饰符使开发人员能够创建必须正确初始化属性或字段的类型,但仍允许使用对象初始值设定项进行初始化。 多个规则可确保此行为: + required 修饰符可应用于在 struct 中声明的字段和属性,以及 class 类型,包括 record 和 record struct 类型。 required 修饰符不能应用于 interface 的成员 ```csharp public class RequiredClass { public required string Name { get; set; } } public struct RequiredStruct { public required string Name { get; set; } } public record RequiredRecordClass { public required string Name { get; set; } } public record struct RequiredRecordStruct { public required string Name { get; set; } } ``` > **Tips:** > + 如果在接口中为字段或属性声明required会报错,提示:<mark>CS0106: 修饰符“required"对该项无效</mark> > > + 使用位置参数声明的记录不能使用required,位置参数是在运行时才会生成记录属性 + 显式接口实现不能标记为 required。 不能在对象初始值设定项中设置它们。 ```csharp public interface IStudyContextModifier { string Name { get; set; } protected int Age { get; set; } } internal class StudyContextModifier : IStudyContextModifier { // 使用显示的方式实现接口属性 required string IStudyContextModifier.Name { get; set; } // 上面的语句会报错:CS0106: 修饰符“required"对该项无效 } ``` > **Tips:**在C#中,实现接口的类不需要使用可访问性修饰符来显式标记接口的实现。这是因为在C#中,接口的成员默认是公共的,因此任何实现该接口的类都必须公开接口的成员。 > > 当我们创建一个类并实现一个接口时,我们只需要确保类中的成员与接口中的成员具有相同的名称和签名。编译器会自动将这些成员视为接口的实现,并默认为公共可访问性,这使得编写和阅读代码更加简洁和清晰。 > > 然而,如果你希望对接口的实现进行访问修饰符的限制,你仍然可以在接口定义中使用访问修饰符来约束接口的成员。但请注意,这只是对接口本身的成员访问性的限制,而不是对实现接口的类的访问性的限制。 >```csharp // 使用上面示例中的接口【IStudyContextModifier】和实现类【StudyContextModifier】 public class StudyContextModifierExample { private string msg = string.Empty; public string Example() { // 通过实现类声明一个接口类型 IStudyContextModifier s = new StudyContextModifier(); s.Name = string.Empty; // 因为接口中Age被定义为protected,因此这里无法通过点符号访问 // ------------------------------------------------------------------ StudyContextModifier m = new StudyContextModifier(); m.Age = 1; // 接口的实现类则可以通过点符号访问Age return msg; } } ``` + 必须初始化必需的成员,但可将其初始化为 null。 如果该类型是不可为 null 的引用类型,则在将成员初始化为 null 时编译器会发出警告。 如果成员根本没有初始化,编译器会发出错误 ```csharp public class NoNullRequired { public required string Name { get; set; } } public static string Example1() { NoNullRequired n = new NoNullRequired() { Name = null }; //如果上面的代码没有初始化Name属性,将会报错:CS9035:必须在对象初始值设定项或属性构造函数中设置所需的成员'No空必需Name return msg; } ``` + 必需的成员必须至少与其包含类型一样可见。 例如,public 类不能包含 protected 的 required 字段。 此外,必需的属性必须具有至少与其包含类型一样可见的资源库(set 或 init 访问器)。 不可访问的成员不能由创建实例的代码设置 ```csharp public class RequiredAccess { protected required string Name { get; set; } // 上述代码会报错:CS9032: 所需成员 RequiredAccess.Name' 的可见性不能低于包含类型RequiredAccess' 的可见性或更小。 public required string Name { get; } public required string Name { set; } // 上面两行代码也是错误的:CS9034: 必需的成员RequiredAccess.Name' 必须可设置,CS8051: 自动实现的属性必须具有 get 访问器 } ``` + 派生类不能隐藏在基类中声明的 required 成员。 隐藏必需的成员可防止调用方为其使用对象初始值设定项。 此外,重写必需属性的派生类型必须包含 required 修饰符。 派生类型无法删除 required 状态。 派生类型可以在重写属性时添加 required 修饰符 ```csharp public class NoNullRequired { public required string Name { get; set; } public virtual required string Country { get; set; } public virtual string Info { get; set; } } public class Children : NoNullRequired { public string Name { get; set; } // 上面的语句是错误的:CS9031: NoNullRequired.Name' 无法隐藏所需的成员 Children.Name(派生类不能隐藏在基类中声明的 required 成员) public override string Country { get; set; } // 上面的语句是错误的:CS9030: 必须需要Children.Country',因为它会覆盖必需的成员“NoNullRequired.Country,要正确的重写需要加上 required(基类抽象和虚拟属性有required修饰符时,子类重写时也必须有required修饰符) public override required string Info { get; set; } // 派生类型可以在重写属性时添加 required 修饰符 } ``` + 当类型参数包含 new() 约束时,不能将具有任何 required 成员的类型用作类型参数。 编译器无法强制在泛型代码中初始化所有必需的成员 ```csharp public class TRequired<T> where T : new() { } public static void Example() { TRequired<NoNullRequired> t = new TRequired<NoNullRequired>(); //上面的代码提示错误:CS9040:'NoNullRequired' 无法满足泛型类型或方法'T'中参数 'TRequired<T>的 'new()’约束,因为 'NoNullRequired'具有必需的成员 } ``` + 不允许对记录上的位置参数声明使用 required 修饰符。 可以为包含 required 修饰符的位置属性添加显式声明 ```csharp public record RecordClass(string Name, int Age) { public required string Info { get; set; } } public static void Example() { RecordClass rc = new RecordClass("曹操", 60) { Info = "大汉丞相"}; } ``` > **Tips:**记录位置参数的写法本身就是必须(required)的only-write属性 ### 1.1. SetsRequiredMembers 属性 某些类型(如位置记录)使用主构造函数初始化位置属性。 如果其中任一属性包括 required 修饰符,则主构造函数将添加 SetsRequiredMembers 属性。 这表示主构造函数初始化所有必需的成员。 可以使用<mark>System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute</mark> 特性编写自己的构造函数。 但是,编译器不会验证这些构造函数是否初始化所有必需的成员。 该特性会转而向编译器断言构造函数会初始化所有必需的成员。 SetsRequiredMembers 特性会将这些规则添加到构造函数: + 链接到另一个使用 SetsRequiredMembers 属性批注的构造函数(this() 或 base())的构造函数还必须包含 SetsRequiredMembers 属性。 这可确保调用方能够正确使用所有适当的构造函数。 + 如果任何成员为 required,则为 record 类型生成的复制构造函数应用 SetsRequiredMembers 属性。 >**Tips:**SetsRequiredMembers 禁用编译器检查所有 required 成员在创建对象时是否已初始化。 请谨慎使用。 下面的代码显示了对 FirstName 和 LastName 属性使用 required 修饰符的类层次结构: ```csharp 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] // 这里使用base访问基类的构造函数,同样也需要加SetsRequiredMembers特性,否则会报错:CS9039: 此构造函数必须添加 'SetsRequiredMembers',因为它链接到具有该属性的构造函数. public Student(string firstName, string lastName) : base(firstName, lastName) { } public double GPA { get; set; } } public static string Example4() { Person p = new Person("关羽","潘凤"); // 调用没有使用对象初始值设定项进行初始化,这是因为 SetsRequiredMembers 特性的作用,它让编译器不去检查属性的必须限制,而有对象的构造函数去对这些位置属性进行初始化 return msg; } ``` > **Tips:<mark>SetsRequiredMembers 属性</mark>** SetsRequiredMembers 属性通知编译器构造函数设置了该类或结构中的所有 required 成员。 编译器假定任何具有 System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute 属性的构造函数都会初始化所有 required 成员。 调用此类构造函数的任何代码都不需要对象初始值设定项来设置所需的成员。 添加 SetsRequiredMembers 特性主要用于位置记录和主要构造函数。 [========] ## 参考资料: > **微软中国官网:** [required 修饰符](https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/required) [C# 编译器解释的杂项属性](https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/attributes/general#setsrequiredmembers-attribute)
扫一扫手机看
点击排行
windows 文件资源管理器使用
Layui 弹窗open使用说明
SQL Server 中字符串函数使用
C# 使用QQ邮箱代理做邮件接收功能
SQL Server关于apply的两种形式cross apply 和 outer apply
ASP.NET MVC 模型的自定义验证
nvm安装及常用命令
SQL Server 中数据类型转换
SQL Server 中WITH AS短语的使用
IE浏览器下AJAX缓存问题导致数据不更新的解决办法
订阅号