C#将主构造函数参数设置为只读
内容提要
C# 12 引入了主构造函数的新功能,允许在类声明中定义构造函数。这对于定义不可变类型很有用。编译器不强制参数的不变性,但可以使用只读字段或Roslyn分析器解决此问题。
延伸解读
主构造函数参数默认可变,与 record 不同
C# 12 的主构造函数参数在类中默认是可变的,编译器不会强制其只读。文章示例显示,在 Foo 类中可以直接对参数 value 重新赋值,而不会产生编译错误。这与 record 类型中参数默认只读的行为不同,因此开发者若期望参数不可变,需要额外处理。
只读字段方案简单但增加样板代码
为确保主构造函数参数不被修改,可以声明一个与参数同名的 readonly 字段,并将参数值赋给该字段。这样后续对字段的赋值会触发编译错误 CS0191。但文章指出,这种方法会引入大量样板代码,尤其当参数较多时,代码会显得冗余。
Roslyn 分析器可自动检测参数赋值
另一种方案是使用 Roslyn 分析器,例如 Meziantou.Analyzer,它提供诊断规则 MA0143,能报告主构造函数参数的所有赋值,以及作为 ref 或 out 参数的使用情况。安装该包后,分析器会在编译时提示潜在的可变操作,帮助开发者在不添加样板代码的情况下维护参数只读性。
Q&A
C# 12 的主构造函数是什么?
C# 12 引入的主构造函数允许直接在类声明中定义构造函数参数,例如 `public class Foo(double value)`,参数可在整个类中使用。
主构造函数适合用来定义不可变类型吗?
是的,主构造函数对于定义不可变类型很有用,但编译器不会强制参数不可变,参数仍然可以被修改。
为什么主构造函数的参数不是只读的?
因为 C# 编译器不强制主构造函数参数的不变性,允许在类的方法中重新赋值参数,这与 records 的行为不同。
如何让主构造函数的参数变为只读?
可以创建一个与参数同名的 readonly 字段,并将参数值赋给该字段,例如 `private readonly double value = value;`,但这样会增加样板代码。
有没有工具可以检测主构造函数参数被修改?
可以使用 Roslyn 分析器,例如 Meziantou.Analyzer,它提供诊断规则 MA0143,报告主构造函数参数的所有赋值或作为 ref/out 参数的使用。
如何安装 Meziantou.Analyzer 来检查主构造函数参数?
可以通过命令 `dotnet add package Meziantou.Analyzer` 安装该包,安装后规则 MA0143 会报告主构造函数参数的所有赋值。