【C#】null許容コンテキスト

Null安全(Null Safety)の実現

1965年にnull参照が発明されてから、多くの言語にnullが採用されてきた。

nullは便利だが、一方で数々の脆弱性やnull参照によるシステムクラッシュの原因となった。

プログラマーたちはnullが入り込むかもしれないという懸念にいつも悩まされてきた。

そうした背景から、現在ではnull安全(Null Safety)を採用する言語が増えてきつつある。

null安全とは、nullをデフォルトで非許容にしたり、null参照例外が発生しうるコードをコンパイルエラーにする等の仕組みのことである。

この流れを汲み、C#でもVersion8.0にて「null許容参照型」が導入された。

これまでC#では、すべての参照型がNull許容型であった。

しかし、それでは安全性に問題があるため、nullを明示的に許可した場合のみnull許容型にしようというのが「null許容参照型」である。

これまでのように型名のみで宣言された場合は、null非許容となる

nullを許可したい場合は型名に?サフィックスを付ける

これは値型にnullを許可する「null許容値型」の書式と同じだが、null許容値型がNullable<T>というもとの型とは全く別の型になるのに対し、参照型の場合はアノテーション(コンパイラが判断するための注釈)にすぎず、内部的には許容型も非許容型も同じ型となる。

Null許容コンテキストと#nullableディレクティブ

C#8.0より前では、参照型に?をつけない状態でnull許容型となっていた。

しかし、8.0では逆に、参照型に?をつけない状態ではnull非許容型となる。

そのためNull非許容がデフォルトとなると、これまでに書かれたコードでは大量の警告が発生してしまう。(下位互換性を保つためにエラーにはならない)

C#は大規模なプロジェクトにも多く用いられる言語であり、このような破壊的変更には非常に慎重であり、下位互換性を保つように配慮されている。

今回のバージョンアップで既存のコードに問題が発生しないように、null許容参照型は既存のコードではオプトイン機能となっており、デフォルトではOFFとなっている。

(オプトイン・・・デフォルトではOFFになっており、明示的に許可することでONとなること)

新規でプロジェクトを作成するとデフォルトでnull許容参照型がONになっている。

この、null許容参照型が有効になっているかどうかを指してnull 許容コンテキストという。

null許容コンテキストをプロジェクト単位で指定するには、プロジェクトファイルの<Nullable>プロパティをenableまたはdisableにする。enableにすると、null許容参照型が有効となる。

また、nullableディレクティブを使い、null許容コンテキストを行単位で細かく切り替えることができる。

nullableディレクティブを大雑把に説明すると以下のようになっている。下の2つは主に既存のコードを段階的にnull許容参照型に移行する過程で使われる。

#nullable disable null許容参照型OFF C#7.3以前の仕様。参照型はすべてnull許容型。
#nullable enable null許容参照型ON C#8.0からの仕様。参照型でnullを使う場合は?が必要。
#nullable restore プロジェクト全体のデフォルトに戻る。
#nullable enable annotations 警告は出したくないが、null許容参照型(?サフィックス)だけ使いたい場合に使用。
#nullable enable warnings 警告だけを出したい場合に使用。


細かい仕様は以下。

#nullable disable
C# 7.3 以前と同様

  • Null 許容の警告は無効
  • 参照型の変数はすべてnull 許容参照型(未指定のnull許容
  • 参照型の変数にnullを代入できる
  • null 許容参照型を宣言できない(?サフィックスの使用不可)
  • null 免除演算子 ! を使用しても警告は出ないが、効果はない

#nullable enable
すべての null 参照分析とnul許容参照型の機能が有効になる。

  • 新しい null 許容のすべての警告が有効
  • ?サフィックスを付けない参照型の変数はすべてnull 非許容参照型
  • null非許容型の変数にnullを代入すると警告が出る
  • null 許容参照型の宣言ができる(?サフィックスの使用可)
  • null 免除演算子!を使用できる。null免除演算子はnull に割り当てられる可能性があるという警告をださないようにすることができる。

#nullable enable annotations
アノテーション(?サフィックス)のみを許可。警告は出さない。

  • null 許容の新しい警告はすべて無効
  • null非許容型の変数にnullを代入できる
  • null 許容参照型の宣言ができる(?サフィックスの使用が可能)
  • ?サフィックスを付けない参照型の変数はすべてnull 非許容参照型
  • null 免除演算子 ! を使用しても警告は出ないが、効果はない
  • コードがnullを逆参照する可能性がある場合も、コンパイラはnull分析を実行せず警告を出さない。

#nullable enable warnings
すべてのnull参照分析を実行し、警告のみを出す。

  • 新しい Null 許容のすべての警告が有効。
  • null 許容参照型を宣言する ? サフィックスを使用すると警告がでる。
  • 参照型の変数はすべて null にすることができる。 ただし、? サフィックスを使用して宣言しない限り、メソッドの左中括弧でメンバーはnullではないとみなされる。
  • null 免除演算子 ! を使用できる。
  • コンパイラはすべての null 分析を実行し、 null を逆参照する可能性がある場合に警告を出す。
ディレクティブ参照型?の使用警告の出力?を付けない型への
nullの代入
制御フロー解析と
逆参照の警告
!の効果
disableすべてnull許容  警告×××
enable?なし:null非許容
?あり:null許容
警告
disable annotationsすべてnull許容警告×××
enable annotations?なし:null非許容
?あり:null許容
×××
disable warningsすべてnull許容警告×××
enable warningsすべてnull許容※警告警告×

#nullable enableとdisable annotations,disable warningsを併用することもできる。

#nullable enable コンテキスト中でdisable annotations,disable warningsを使った場合の挙動は以下。

参照型?の使用警告の出力?を付けない型への
nullの代入
制御フロー解析と
逆参照の警告
!の効果
disable annotationsすべてnull許容警告
disable warningsすべてnull許容×××

コメント

タイトルとURLをコピーしました