BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース C#の新機能: nullチェック演算子

C#の新機能: nullチェック演算子

原文(投稿日:2020/07/01)へのリンク

6月24日のC# Language Design Meetingで、Microsoftは、パラメータnullチェック構文の一部を変更した。"Type parameterName!"から"Type parameterName!!"に変更して、実質的に新しい"nullチェック演算子"を導入したのだ。

これにより、単一の感嘆符が2つの似て異なる意味を持つ、という問題が回避される。

void MethodA(string a!)

string a = b!;

上の例では、a!が"これがnullでないことを検証せよ"という意味であるのに対して、b!は"チェックしないでnullではないと仮定せよ"という意味になる。

2重感嘆符に落ち着く前には、他の構文も候補として挙がっていた。

void M(string param!)
void M(string param!!)
void M(string!param)
void M(string !param)
void M(checked string param)
void M(string param ??throw)
void M(string param is not null)
void M(notnull string param)
void M(null checked string param)
void M(bikeshed string param)
void M([NullChecked("Helper")] string param)
/* contract precondition forms */
void M(string param) Requires.NotNull(param)
void M(string param) when param is not null

"自転車置き場(bikeshed)"というキーワードを疑問に思う方のために説明すると、これはパーキンソンの凡俗法則(Parkinson's Law of Triviality)を言っているのだ。すなわち、委員会は注意の大半を些細な問題、例えば原子炉外の自転車置き場をどうするか、といったようなことに集中する傾向がある一方で、本当に重要な問題、例えばどの原子炉を使用するかといった問題を無視している、ということである。おそらくは6月17日のC# Language Design Meetingの書記が、会議の内容に呆れて書いたものなのだろう。

C# 9のタイムフレームでは、nullチェック演算子(!!)は引き続きパラメーのみに限定して使用されるが、開発者や言語デザイナは、それが他でも使用可能になることをすでに予測している。

説明のために、このような関数と文を考えてみよう。

string?Foo();
string x1 = Foo();

null許容参照型(nullable reference types)が可能になれば、これはコンパイル時に警告を受けることになるだろう。しかし開発者は、Foo()がこのコンテキストでnullを返さないことを知っているのかも知れない。従って開発者は、感嘆符(!)で例外を排除する。

string x2 = Foo()!;

これは"Foo()の結果をx2にアサインせよ、ただし、Foo()はnullを返さないものとする"、ということだ。

この仮定は現時点では受け入れられるかも知れないが、将来的にFoo()が変更された時に、意図していないnullが返される可能性がある。これに対処するため、C#の将来のバージョンでは2重感嘆符(!!)が使用可能になるかも知れない。

string x3 = Foo()!!;

これは意味を、"Foo()がnullを返した場合には例外をスローし、そうでない場合は結果をx3にアサインせよ"に変えるものだ。

最初に思い付くのは、スローされる例外はおそらくInvalidOperationExceptionで、現在実行中の式が例外のメッセージとして含まれる、というものだろう。しかしこれは、例外の型はエラーが呼び出し元、ライブラリ、環境のいずれで発生したものかを示すべきであるという点からは問題がある。InvalidOperationExceptionは呼び出し元に問題があったことを暗示しているが、多くの場合これは、"ライブラリの作者が不適切な仮定をした"シナリオの面が強いはずだからだ。

Ed Ball氏は次の疑問を投げかけている。

!!演算子は、Nullable<T>Valueアクセスに変換されるのでしょうか?

void MethodOne(string?text, DateTime?dateTime)
{
    MethodTwo(text!!.Substring(1)); // throws InvalidOperationException if null
    MethodThree(dateTime!.Value.AddHours(1)); // throws InvalidOperationException if null
    MethodThree(dateTime!!.AddHours(1)); // throws InvalidOperationException if null
}

この記事に星をつける

おすすめ度
スタイル

BT