C# 9.0 の確認の目次はこちら
■ init 専用セッター
ドキュメントはこちら
初期化時にだけ値をセットできる素敵なプロパティを作れます。もっとわかりやすく簡単に言うと、イミュータブルなオブジェクトが作れます。
初期化とは
- コンストラクタ
- 初期化子 ( new XXXX { プロパティ名 = 値} )
- with 式 ( 型名 新しい変数 = 変数 with { プロパティ名 = 値 }; )
プロパティの宣言で普段 set と書いている所を init と書くと使えます。
public int MyProperty { get; init; }
■ init の確認
実際に init と書いてみましょう
// init の Property の場合 public record Saitama { public string InitProperty { get; init; } public Saitama() => InitProperty = "value5"; //public void SetValues() => InitProperty = ""; // これはエラー。初期化専用なので。うれしい } static void Main(string[] args) { var saitama1 = new Saitama { InitProperty = "" }; // これはエラーにならない。初期化専用なので。うれしい var saitama2 = saitama1 with { InitProperty = "" }; // これはエラーにならない。初期化専用なので。うれしい //saitama2.InitProperty = ""; // これはエラー。初期化専用なので。うれしい }
プライベートなメソッド内でエラーになり変更不能になっていることがわかります。
そして初期化は可能で変更は不可です。素敵。これが init です。
■ 類似の手法
類似の手法を書いてみて init と違い不完全であることを確認していきましょう。
読み取り専用フィールド
// ReadOnly の Field の場合 public record Saitama { public readonly string ReadOnlyField; public Saitama() => ReadOnlyField = "value1"; //public void SetValues() => ReadOnlyField = ""; // これはエラー。ReadOnly なので。うれしい } static void Main(string[] args) { //var saitama1 = new Saitama { ReadOnlyField = "" }; // これはエラー。ReadOnly なので。うれしくない //var saitama2 = saitama1 with { ReadOnlyField = "" }; // これはエラー。ReadOnly なので。うれしくない //saitama2.ReadOnlyField = ""; // これはエラー。ReadOnly なので。うれしい }
変更できないのはいいですが、初期化もできなくなってしまいます。こまります。
普通の変更可能なプロパティ
// set と get の Property の場合 public record Saitama { public string SetGetProperty { get; set; } public Saitama() => SetGetProperty = "value2"; public void SetValues() => SetGetProperty = ""; // これはエラーにならない。set できるので。うれしくない } static void Main(string[] args) { var saitama1 = new Saitama { SetGetProperty = "" }; // これはエラーにならない。set できるので。うれしくない var saitama2 = saitama1 with { SetGetProperty = "" }; // これはエラーにならない。set できるので。うれしくない saitama2.SetGetProperty = ""; // これはエラーにならない。set できるので。うれしくない }
普通に変更できます。変更可能にしたので当たり前ですが。こまります。
読み取り専用プロパティ
// get のみの Property の場合 public record Saitama { public string GetOnlyProperty { get; } public Saitama() => GetOnlyProperty = "value3"; //public void SetValues() => GetOnlyProperty = ""; // これはエラー。set できないので。うれしい } static void Main(string[] args) { //var saitama1 = new Saitama { GetOnlyProperty = "" }; // これはエラー。set できないので。うれしくない //var saitama2 = saitama1 with { GetOnlyProperty = "" }; // これはエラー。set できないので。うれしくない //saitama2.GetOnlyProperty = ""; // これはエラー。set できないので。うれしい }
変更できないのはいいですが、初期化もできなくなってしまいます。こまります。
セッターが private のプロパティ
public record Saitama { public string PrivateSetProperty { get; private set; } public Saitama() => PrivateSetProperty = "value4"; public void SetValues() => PrivateSetProperty = ""; // これはエラーにならない。private では set できるので。うれしくない } static void Main(string[] args) { //var saitama1 = new Saitama { PrivateSetProperty = "" }; // これはエラー。set できないので。うれしくない //var saitama2 = saitama1 with { PrivateSetProperty = "" }; // これはエラー。set できないので。うれしくない //saitama2.PrivateSetProperty = ""; // これはエラー。set できないので。うれしい }
初期化できないし、メソッド内で変更できてしまっています。こまります。
■ まとめ
まあ、当たり前の結果になりました。
けれどもこの確認で確かに init 専用セッターでなければイミュータブルとして不完全であることが確認できました。
時代はイミュータブルです。積極的に使っていきましょう。