C# 11 的 required members 机制通过 required 关键字在编译期强制对象初始化器中赋值指定字段或自动属性,不依赖构造函数,支持继承和 init 属性,但非运行时约束,不影响序列化与反射。

C# 11 引入的 required members(必需成员)机制,主要是为了解决对象初始化时某些字段或属性“必须赋值但又不想写构造函数”的问题。它不依赖构造函数参数,而是通过 required 关键字标记字段/属性,在编译期强制要求在对象初始化器中设置——没赋值就报错。
required 成员的基本用法
只需在类或结构体的字段或自动属性前加 required 修饰符即可。该成员必须在对象初始化器(new TypeName { ... })中显式赋值。
- 仅支持实例字段和自动属性(不支持手动实现 get/set 的属性)
- 不能用于
static、const、init(init-only 属性本身可被标记为 required)、readonly字段(除非同时用init) - 支持继承:基类的 required 成员,派生类初始化时也必须提供
示例:
public class Person
{
public required string Name { get; set; }
public required int Age { get; set; }
public string? Email { get; set; } // 非 required,可选
}
// ✅ 正确:Name 和 Age 都在初始化器中赋值
var p = new Person { Name = "Alice", Age = 30 };
// ❌ 编译错误:缺少 required 成员 Age
// var p2 = new Person { Name = "Bob" }; // 报错 CS8852
与构造函数和 init-only 属性配合使用
required 成员可和 init 属性共存,适合构建不可变但需灵活初始化的对象。
-
required init属性:只能在初始化器中设一次,之后不可改 - 仍允许无参构造函数存在,但调用后若未用初始化器赋值 required 成员,编译失败
- 也可搭配自定义构造函数,但构造函数内部赋值不会绕过 required 检查(即:仍需在初始化器中出现)
示例:
public class Product
{
public required init string Sku { get; set; }
public required init decimal Price { get; set; }
public string? Description { get; set; }
}
// ✅ 合法:init 属性 + required 保证初始化完整性
var prod = new Product { Sku = "P123", Price = 29.99m };
// ❌ 错误:Sku 和 Price 是 required init,不能省略
// var bad = new Product(); // 编译失败
序列化与反射注意事项
required 成员本身是编译器特性,不影响运行时行为,但会影响部分框架行为:
- JSON 序列化(如 System.Text.Json)默认不感知
required,需手动配置验证逻辑或结合[Required](DataAnnotations) - 反射中无法直接判断某属性是否被标记为
required(无对应元数据),这是编译期检查,非运行时属性 - 源生成器(Source Generators)可读取语法树识别
required,适合构建验证或文档工具
常见误区提醒
别把 required 当作运行时约束或数据验证手段:
- 它不等于
[Required](DataAnnotations),后者用于模型绑定和验证,运行时生效 - 它不能替代构造函数逻辑(比如校验 Age > 0),只是确保字段被“写”了,不管写的是不是有效值
- 如果用了 record 或 record struct,
required依然适用,但要注意 primary constructor 参数和 required 属性的分工
基本上就这些。required members 是轻量级、编译期友好的初始化保障机制,适合简化 DTO、配置类、API 请求模型等场景,不复杂但容易忽略细节。










