C# 8のNull許容参照型(nullable refence types)の作業は継続されており、最終リリース前に対処する必要があるエッジケースと、開発者が書く必要がある定型コードを削減する新しい機会を明らかにしている。
以下はNull許容型に対するオープンクエスチョンである:
MaybeNull
とNotNull
のどちらが優先されるか?AllowNull
とNotNull
のどちらが値型に許可されるべきか?!
は警告なしで最上位レベルのNull許可を変更するべきか?- ref引数は、常に代入されると仮定するべきか?
- メンバーのNull許可状態を維持して変換するべきか?
var?
をサポートするべきか、その場合の未解決問題はなにか?- この方針に従って
var? (x, y) = ...
の分解を可能にするか? typeof(string?)
は、nullableアノテーションを尊重できないが、許可する(もしくは禁止する)べきか?- フロー分析でnullableアノテーションを計算するとき、コンテキストを使用する必要があるか?
- 動的呼び出しの結果は、一般的に静的分析のスコープ外のため、non-nullとして扱うべきか?
その他の質問にも答えた。これはコードの書き方に影響を与えるいくつかのハイライトである。
- 条件付き呼び出しのNull許容性(
x?.F()
)は常にNull許容である。 - Throwステートメントとthrow式は、オペランドがnullになる可能性があるときに警告する。
- 到達不能なコードにNull許容性警告は表示しない。
- 匿名型のNull許容性は推論されたシグニチャの一部である。
宣言的引数のNullチェック
Null許容参照型の問題の1つは、コンパイラに対する単なる提案である。パラメータをnon-nullableとしてマークしたとしても、特にリフレクションやdynamicを使っている場合には、誰かが誤ってnullを渡すことを止めることができない。つまり関数の先頭にnull引数チェックをなくすことはできないということである。
引数のnull検証の単純化において、コンパイラにnullチェックを生成するように伝えることができる。2つの構文が提案されている。
void Insert(string s!)
void Insert(string! s)
感嘆符オペレーター(!
)は、型名とパラメータ名のどちらかに使われる。1つ目のバージョンの引数は、関数の実装詳細であり、メソッドシグニチャの一部ではない。2つ目の引数は、より一貫したNull許可バージョン(void Insert(string? s)
)で、メソッドシグニチャであるべきである。シグニチャの一部であることはとても重要で、インターフェイスメソッドにも適用できる。そして継承とメソッドのオーバーライドに対しても疑問を投げかける。
別の疑問は、それがどのように実装されるのかである。オプションは次の通り:
- C#はILのインラインチェックを発行する
- C#はILのヘルパーメソッド呼び出しを発行する
- C#はタグを発行するだけなので、JITプロセスはチェックの実行方法を決定できる
もう1つの疑問は、型がNull許容(int?
)だが、nullチェックが望まれているときになにが起きるのか。サポートされている場合、(void Insert(int?! i)
)のシグニチャに矛盾が生じる可能性がある。
カスタムシンタックスの代わりに属性([NotNull]
)を使ったものはまだ議論されていない。より冗長ではあるが、宣言的引数チェックの他の形式の前例になるだろう。