Unity2021.2でinitアクセサを使う
Unity2021.2からC#9の一部機能が使えるようになります。
しかしドキュメントによるとInit only settersは未サポートとなっています。
実際にinitアクセサを使おうとするとIsExternalInitが必要というエラーが出力されます。これは.NET5.0以降のクラスなのでUnityには入っていません。なので自前で定義します。
具体的には以下のコードを貼っておけばOKです。
using System.ComponentModel;
namespace System.Runtime.CompilerServices
{
[EditorBrowsable(EditorBrowsableState.Never)]
public static class IsExternalInit
{
}
}
これだけで使えるようになります。公式には未サポートなので自己責任で使ってください。
initアクセサとは
そもそもinitアクセサとは何かについても説明しておきます。
プロパティ宣言でsetの代わりにinitが使えます。
public class Class
{
public int Value { get; init; }
}
initで宣言されたプロパティは初期化時にだけ値を代入できるようになります。
initならprivate setよりスコープが狭いとは言えないことに注意してください。
次のコードの3と4での代入はprivate setではエラーになるところがinitでは通ってしまいます。
public class Parent
{
public int Value { get; init; } = 1; // 1. プロパティ初期化子で代入
public Parent()
{
Value = 2; // 2.コンストラクタ内で代入
}
}
public class Child : Parent
{
public Child()
{
Value = 3; // 3.子のコンストラクタ内で代入
}
}
var p = new Parent
{
Value = 4, // 4.オブジェクト初期化子で代入
};
特に4には注意が必要です。initではクラスの外からどんな値が代入されるか分かりません。
初期化時だけ代入したい + クラスの外から代入されたくない、というときにはinitではなくprivate initを使います。上のコードでinitの部分をprivate initにすれば3と4がエラーになります。
もちろんprotected initにすれば4だけがエラーになります。
initは初期化以外で代入できなくするだけの機能です。それ以外はsetと同じなのでスコープの設定も忘れないようにしてください。