null許容型をまねて、null不可能型とかを妄想してみた
null許容型は、値型なのにnullを格納できる型で、C#ではこう書く。
int? i = null; // nullが格納できる!
これと同じ考え方で、参照型なのにnullを格納できない型とかあると便利じゃね?と言うことで、どんな感じになるのか以下妄想。
null許容型は値型の末尾に?を付けることを真似て、null不可能型では参照型の末尾に!を付ける。
// stringのnull不可能型には文字列リテラルかstringのnull不可能型が初期化/代入可能 string! str = ""; string! str2 = str; // null不可能型にnullは初期化/代入不可 // str = null; // strに通常のstringは初期化/代入不可 string str3 = ""; // str = str3; // ??演算子の最右項に文字リテラルかnull不可能型を置けばコンパイル可能 str = str3 ?? ""; // null不可能型は??演算子の最右項以外には置けない // str = str2 ?? ""; // null不可能型を通常の型に初期化/代入可能 str3 = str2;
null指定型というのも妄想してみた。
null指定型の変数にnullを初期化/代入すると、nullの代わりに指定した値が代入される。
// クラスレベルで指定する(sealedの必要あり) public sealed class Hoge ifnullthen Hoge.None { // static readonlyのnull不可能型のみ指定可能 // public classはpublic、internal classはinternal以上の可視性が必要 public static readonly Hoge! None = new Hoge(); }
クラスレベルでの指定は制限が大きいが、より制約の小さい変数レベルの指定も可能。
public class Hoge { internal static readonly Hoge! None = new Hoge(); internal static readonly Hoge! None2 = new Hoge(); } // :の後にnullの代わりに使用する値を指定する // その変数を使用するスコープで見えるnull不可能型が指定可能 Hoge:Hoge.None h1 = null; // クラスが同じならHoge.は省略可能 Hoge:None2 h2 = h1; // この場合どーすれば・・・ // setterでフックするならHoge.Noneだろうし、 // getterでフックするならHoge.None2になる // setterでフックしたほうが効率はいいだろうけど、 // getterでフックしたほうが自然かな
うーん、もっと煮詰めれば結構面白いかも。