主构造函数是C# 12+中强制的初始化入口,不提供参数无法实例化(除非显式添加无参构造函数);所有其他实例构造函数必须通过this(...)显式调用它,参数仅在类型体内可用,需手动赋值为字段或属性,普通类中不自动生成属性(记录类型除外)。

主构造函数不是“语法糖”,而是初始化逻辑的强制入口——不提供参数就无法实例化,除非你显式加了无参构造函数。
主构造函数必须被所有其他构造函数调用
当你在 class 或 struct 声明里写上参数(如 class Person(string name, int age)),C# 12+ 就认定这是主构造函数。此时:
- 所有其他实例构造函数(比如
public Person() { ... })必须通过this(...)显式调用主构造函数,不能绕过 - 编译器不会帮你生成默认无参构造函数;没写,就不能用
new Person() - 主构造函数参数只在类型定义体内可用,不是字段也不是属性——想持久化得手动赋值,比如
public string Name { get; } = name;
主构造函数参数不能直接当属性用(记录类型除外)
这是最容易混淆的点。普通类/结构的主构造函数参数 不是自动属性:
class User(string name) // ← name 是参数,不是字段
{
// ❌ 编译错误:name 不是成员
// public string Name => name;
<pre class="brush:php;toolbar:false;">// ✅ 正确:显式声明只读属性并初始化
public string Name { get; } = name;
// ✅ 也可赋给私有字段
private readonly string _name = name;}
而 record class User(string name) 会自动生成 public string Name { get; init; },行为完全不同。
与 base() 调用共存时顺序很关键
如果类继承自基类,主构造函数参数可以传给 base(...),但必须确保基类构造函数先执行:
class Animal(string species) : LivingThing(species.ToUpper())
{
// ✅ 合法:主构造参数用于 base 调用
// ✅ Animal 实例构造函数体在 base 执行完后才运行
}
<p>class LivingThing(string label)
{
public string Label { get; } = label;
}
- 不能在
base(...)中使用this成员或未初始化字段 - 主构造参数可用于
base调用,但不能用于字段初始值设定项中调用this方法(因为此时对象还没完全构造)
struct 主构造函数要求更严格
结构类型用主构造函数时,要注意:default(MyStruct) 不会触发主构造函数(它走零初始化路径),所以:
- 如果你在 struct 里写了字段初始值设定项(如
int Count = 0;),就必须同时提供无参构造函数,否则编译报错 - 主构造函数只在
new MyStruct(...)时运行,default或隐式赋值不触发它 - 别指望主构造函数能拦截所有 struct 实例化路径——它只管
new,不管默认值
真正容易被忽略的是:主构造函数让“构造即验证”变得自然,但也堵死了无参创建的后门。一旦加了参数,你就得面对依赖注入容器是否支持、序列化库能否反射出主构造函数、测试时 mock 是否受限这些问题——这些不在语法层面报错,但会在运行时或集成阶段突然冒出来。


















