我々は以前、プライマリコンストラクタについて、2014年にそれがC# 6およびVB 12の機能候補リストから削除されたことをお伝えした。昨年末、そのプライマリコンストラクタが再び、プロポーザル #2691としてC# 9の機能候補になったのだ。
プライマリコンストラクタの基本的なアイデアは、クラス初期化に必要なボイラプレートコード量を削減することにある。
class C(string x)
{
public string X
{
get => x;
set {
if (value == null)
throw new NullArgumentException(nameof(X));
x = value;
}
}
}
は、次のように翻訳される。
class C
{
private string _x;
public C(string x)
{
_x = x;
}
public string X
{
get => x;
set {
if (value == null)
throw new NullArgumentException(nameof(X));
x = value;
}
}
}
Richard Gibson氏がその有用性をまとめている。
30クラスからなるコードベースから取得した簡単なサンプルでは、22クラス(73パーセント)に明示的なコンストラクタが定義されていて、その中の21(95パーセント以上)は、privateかつreadonlyなフィールドの初期化のみを行うものでした。これらは無駄で、面倒で、自動生成が可能である上、人が読むことは(必要のないものなので)ほとんどない — 通常は読み飛ばされる — ことから、驚くほど多くのバグの発生源となっているのです。
このようなバグは、おもにコンストラクタのパラメータを誤ったフィールドに設定することによって発生する、と氏は言う。
このコンセプトは、我々が"Easier Immutable Objects in C# and VB"で取り上げたレコードの提案と大きくオーバーラップする。MgSam氏によれば、
この提案は、現在のレコードの提案とまったく相容れないものに思われます。この機能がレコードよりも広範に利用可能であるとする提案の内容には、同意できません。この機能で省略可能なボイラプレートが少量であるのに対して、レコード(および関連するGetHashCodeやEquals、ToStringの自動生成)では、多数のシナリオにおいて膨大なボイラプレートを省略できる可能性があります。
HaloFour氏もこのトピックに注目するひとりだ。
レコード機能がC#に提案する内容には、シンメトリックなコンストラクトとデコンストラクトに加えて、特定のプロパティセットに基づいた識別も含まれています。プライマリコンストラクタでは、ひとつのパラメータリストを提供するだけで、そのパラメータがプロパティでもあり、そのリストがプロパティのデコンストラクト可能な順番の指示にもなっています。
C#のレコードに関する提案内容は、ScalaのケースクラスやF#のシングルケースユニオンに近いものですが、これらの言語はいずれも、その構築方法によってコンストラクタを定義しているのです。