required属性是HTML5布尔属性,仅作用于input、select、textarea等可输入表单控件,提交时校验是否为空,不校验格式,提示不可定制,且必须依赖表单提交事件触发。

required 不能加在方法上,也不能当参数修饰符用;它只作用于类或结构体的实例属性/字段,且必须配 set 或 init 访问器——否则编译直接报错。
required 属性必须带 public/internal set,不能是 init-only
很多人写 public required string Name { get; init; } 结果编译失败,报 CS8853。这是因为 required 要求编译器能“看到”一个可写的入口,而 init 访问器在对象初始化后即失效,不满足隐式赋值契约。
- ✅ 允许:
public string Name { get; set; }、public string Name { get; private set; } - ❌ 禁止:
public string Name { get; init; }、public string Name => _name;(无 set)、public readonly string Name;(字段) - 访问器可见性不能低于类型本身:比如
public class Person里不能有protected required string Name
对象初始化器中漏掉 required 成员会触发 CS8852 编译错误
这是最常见报错场景。只要用了 new Person { ... } 语法,所有 required 成员都必须显式出现,缺一个就过不了编译。
- ✅ 正确:
var p = new Person { Name = "Alice", Age = 30 }; - ❌ 错误:
var p = new Person { Name = "Bob" };→ 报 CS8852:“无法为必需的成员‘Age’赋值” - 即使属性类型是不可为空引用类型(如
string),初始化为null也不会报错,但会触发 NRT 警告
构造函数不自动绕过 required,除非打上 [SetsRequiredMembers]
默认情况下,哪怕你写了完整构造函数,编译器仍认为对象没走“初始化路径”,required 成员还是得靠对象初始化器补全。想让构造函数合法接管,必须手动加特性。
- ✅ 合法:
[SetsRequiredMembers] public Person(string name, int age) { Name = name; Age = age; } - ⚠️ 注意:
[SetsRequiredMembers]是纯编译器断言,不校验逻辑——如果你在构造函数里漏赋值,运行时照样是null或default - 普通构造函数(无该特性)+ 对象初始化器,是唯一无需额外标注的组合方式
反序列化和反射可能完全绕过 required 检查
required 是编译期契约,不是运行时防护。这点极易被忽略,尤其在 Web API 或配置加载场景中。
-
JsonSerializer.Deserialize<person>(json)</person>默认不校验 required 字段,结果得到一个Name = null, Age = 0的实例 -
Activator.CreateInstance<person>()</person>也能成功,且不会抛异常 - .NET 8+ 可启用
JsonSerializerOptions.RequireExplicitNullValueHandling = true做有限补救,但非银弹 - 真要杜绝未初始化实例,得配合私有构造 + 工厂方法,或直接用
record(自动禁用无参构造)
真正麻烦的从来不是怎么写 required,而是它只管“有没有赋值”,不管“值合不合理”——比如 Name = "" 或 Age = -5,编译器照放行。验证逻辑还得自己写在 set 里或构造函数中。


















