c# 12 的主构造函数是在 class 或 struct 声明行后直接写括号参数的语法糖,自动生成 private readonly 字段(或 public get-only 属性),不新增关键字,需显式调用、不支持 ref/out/params,不可用于 record 或 partial 类。

什么是 C# 12 的主构造函数(Primary Constructor)
它不是新增一个叫 PrimaryConstructor 的关键字或特性,而是 C# 12 允许你在 class 或 struct 声明行后直接写括号参数,从而隐式定义一个构造函数并自动捕获参数为 private readonly 字段(或可选地提升为属性)。它本质是语法糖,编译后仍生成常规构造函数和字段。
怎么写一个带主构造函数的 class
把参数直接写在类名后面,用括号包裹;参数会默认成为私有只读字段,名称与参数名一致(注意大小写)。
public class Person(string name, int age)
{
// name 和 age 已自动作为 private readonly 字段存在
public string Name => name;
public int Age => age;
}- 不能在主构造函数参数列表中使用
ref、out、params或可空引用类型标注(如string?)——但可以写string,其可空性由上下文推断 - 若需公开属性,必须显式定义(如上例),主构造参数本身不自动暴露为 public 属性
- 若想让某个参数变成 public auto-property,可用
public修饰符:public class Person(public string Name, int age)——此时Name会生成 public get-only 自动属性,且不再作为私有字段存在
主构造函数和常规构造函数能共存吗
可以,但必须显式调用主构造函数(通过 this(...)),否则编译报错:CS9148: Primary constructor must be invoked by all other constructors。
public class Order(decimal total, string currency) : ICloneable
{
public Order(decimal total) : this(total, "USD") { } // ✅ 正确:调用主构造
<pre class="brush:php;toolbar:false;"><code>public object Clone() => new Order(total, currency);}
- 所有额外定义的构造函数(包括无参构造)都必须以
this(...)开头,且只能调用一次 - 不能在主构造函数里写方法体(比如加日志、校验),它没有函数体;校验逻辑得放在其他构造函数或初始化器里
- 若需要参数校验,常见做法是定义一个私有构造函数做验证,再让主构造函数委托给它(反过来不行,因为主构造必须最先被调)
主构造函数对继承和泛型的影响
主构造参数不会自动参与基类构造调用;子类若要传递参数给父类主构造,必须显式用 : base(...)。泛型约束也需单独声明,不继承自主构造参数类型。
public class Animal<T>(T id) where T : notnull
{
public T Id => id;
}
<p>public class Dog(string name, int age) : Animal<string>(name) // ✅ 显式传参给基类主构造
{
public string Name => name;
}- 主构造函数不改变类的继承规则,但容易让人误以为参数“自动向上透传”,实际必须手动写
: base(...) - 泛型参数若来自主构造,需在类声明处重复声明(如
class C<t>(T value)</t>),不能省略<t></t> - 主构造函数不可用于
record(因为 record 已有自己的紧凑语法),也不支持partial类跨文件拆分主构造参数定义
主构造函数看着简洁,但字段生命周期、访问控制、继承链中的参数流转这些地方很容易漏掉显式声明,尤其从老版本迁移时,别假设参数会“自动变 public”或“自动传给基类”。







