C#将主构造函数参数设置为只读

💡 原文中文,约1000字,阅读约需3分钟。
📝

内容提要

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 会报告主构造函数参数的所有赋值。

🏷️

标签

➡️

继续阅读