どうも、完全コンストラクターパターン大好きマンです。でも、コンストラクターをいちいち書くのは面倒くさい。
インテリコードさんがある程度自動で書いてくれるものの、パラメーター追加時に XML コメントの追加を忘れたり・・・できることならデフォルトコンストラクターで済ませたいです。
初期化子の中で代入すればいいじゃないか、となりますが、初期化し忘れが怖い。
そこを解決してくれる機能が C# 11 で追加されました!
C# 11 で追加された required キーワード と C# 9 ですでに追加されている init キーワード を使って、長ったらしいコンストラクターを書かずに完全コンストラクターパターンを実現してみましょう!
①今までの書き方
internal sealed class UserOld
{
internal string Name { get; }
internal string Email { get; }
internal int Age { get; }
public UserOld(string name, string email, int age)
{
Name = name;
Email = email;
Age = age;
}
}
- プロパティは
get
のみ定義 - コンストラクターですべてのプロパティを初期化
このようにシンプルなクラスだったら気にならないけど、プロパティが増えたり名前が複雑になってくると面倒ですよね。
このクラスを使ってみると・・・
UserOld old1 = new("ひげげ", "higege@higege.com", 45);
UserOld old2 = new("ひげげ", "higege@higege.com"); // CS7036 エラー
②required を使って書いてみる
internal sealed class User
{
internal required string Name { get; init; }
internal required string Email { get; init; }
internal required int Age { get; init; }
public User()
{
}
}
- すべてのプロパティに
required
キーワードをつける - すべてのプロパティに
get
init
を定義する - デフォルトコンストラクターでOK(書かなくても問題ない)
見慣れない required
がありますが、すっきりしています。
このクラスを使ってみると・・・
User user1 = new()
{
Name = "ひげげ",
Email = "higege@higege.com",
Age = 45,
};
User user2 = new()
{
Name = "ひげげ",
Email = "higege@higege.com",
}; // CS9035 エラー
比べてみる
クラスの実装
行数少なくキーワードで属性の説明がされている②が若干わかりやすいか。かといって①がわかりにくいかと言ったらNO。
使用箇所
比較のため①も改行して並べてみます。
UserOld old1 = new(
"ひげげ",
"higege@higege.com",
45);
User user1 = new()
{
Name = "ひげげ",
Email = "higege@higege.com",
Age = 45,
};
いや、やはり使用箇所は断然①でしょう。クラス実装時の面倒よりも、使用箇所の面倒の方がイヤ。
その他の課題
プロパティのルールはどう実装するんだ?①だったらコンストラクターないで順番にチェック、②は init
を実装か。
そうするとクラスの実装のシンプルさが損なわれてしまう・・・うーん。
まとめ
使用箇所の実装量・可読性から、これからも長ったらしいコンストラクターを書いていこうと思います。(チャンチャン