null 診断警告を改善するために、null 許容参照型を使用してコードベースを更新する

null 許容参照型を使用すると、参照型の変数に null 値を割り当てるかどうかを宣言できます。 コンパイラのスタティック分析と、コードが null を逆参照する可能性がある場合の警告は、この機能の最も重要な利点です。 有効にすると、コードの実行時に System.NullReferenceException がスローされないようにするための警告がコンパイラによって生成されます。

コードベースが比較的小さい場合は、プロジェクトの機能をオンにし、警告に対処して、改善された診断の利点を享受できます。 コードベースが大きい場合は、より構造的なアプローチで時間をかけて警告に対処する必要があり、さまざまな種類やファイルの警告に対処する際に一部の機能を有効にする必要があります。 この記事では、コードベースを更新するためのさまざまな戦略と、その戦略に伴うトレードオフについて説明します。 移行を開始する前に、null 許容参照型の概要を参照してください。 コンパイラのスタティック分析、"null の可能性あり" および "null 以外" の "null 状態" 値、および null 許容注釈について説明します。 これらの概念と用語について理解したら、コードを移行する準備が整います。

移行を計画する

コードベースの更新方法に関係なく、目標は、null 許容警告と null 許容注釈をプロジェクトで有効にすることです。 この目標を達成すると、プロジェクトで <nullable>Enable</nullable> を設定できるようになります。 他の場所で設定を調整するためのプリプロセッサ ディレクティブは必要なくなります。

最初の選択肢は、プロジェクトの既定値を設定することです。 選択肢は次のとおりです。

  1. "null 許容無効を既定値とする": プロジェクト ファイルに Nullable 要素を追加しない場合、"無効" が既定値です。 新しいファイルをコードベースに積極的に追加しない場合は、この既定値を使用します。 主なアクティビティは、null 許容参照型を使用するようにライブラリを更新することです。 この既定値を使用することは、コードを更新するときに各ファイルに null 許容のプリプロセッサ ディレクティブを追加することを意味します。
  2. "nul 許容有効を既定値とする": 新しい機能を積極的に開発している場合に、この既定値を設定します。 null 許容参照型と null 許容のスタティック分析から利点を得るために、完全に新しいコードを必要とします。 この既定値を使用すると、#nullable disable を各ファイルの先頭に追加する必要があります。 各ファイルの警告に対処するとき、このプリプロセッサ ディレクティブを削除します。
  3. "null 許容警告を既定値とする": 2 フェーズ移行の場合は、この既定値を選択します。 最初のフェーズで、警告に対処します。 2 番目のフェーズで、変数の予期された "null 状態" を宣言するために、注釈を有効にします。 この既定値を使用すると、#nullable disable を各ファイルの先頭に追加する必要があります。
  4. "null 許容注釈" を既定値とする。 警告に対処する前にコードに注釈を付けます。

null 許容有効を既定値とすると、すべてのファイルにプリプロセッサ ディレクティブを追加する前処理が増えます。 利点は、プロジェクトに追加されるすべての新しいコード ファイルで null 許容が有効になることです。 新しい作業はすべて null 許容対応になります。既存のコードのみを更新する必要があります。 ライブラリが安定していて、開発の主眼が null 許容参照型を採用することにある場合は、null 許容無効を既定値とする方がうまく機能します。 API に注釈を付けるときに、null 許容参照型を有効にします。 終了した時点で、プロジェクト全体について null 許容参照型が有効になります。 新しいファイルを作成する場合は、プリプロセッサ ディレクティブを追加し、null 許容対応にする必要があります。 チームの開発者がそれを忘れた場合、その新しいコードは、すべてのコードを null 許容対応にするという作業が発生します。

どちらの戦略を選択するかは、プロジェクトで行われているアクティブな開発の量によって異なります。 プロジェクトが成熟して安定しているほど、2 番目の戦略がふさわしくなります。 開発中の機能が多いほど、最初の戦略が優れています。

重要

グローバルな Null 許容コンテキストは、生成されたコード ファイルに適用されません。 いずれの方法でも、Null 許容コンテキストは、生成済みとしてマークされているすべてのソース ファイルに対して "無効になります"。 これは、生成されたファイル内のどの API にも注釈が付けられないことを意味します。 ファイルが生成済みとしてマークされる方法は 4 つあります。

  1. .editorconfig で、そのファイルに適用されるセクションで generated_code = true を指定します。
  2. ファイルの先頭にあるコメントに <auto-generated> または <auto-generated/> を配置します。 これは、コメント内の任意の行に配置できますが、コメント ブロックはファイル内の最初の要素である必要があります。
  3. ファイル名を TemporaryGeneratedFile_ で開始します
  4. ファイル名の末尾を .designer.cs.generated.cs.g.cs、または .g.i.cs にします。

ジェネレーターは、#nullable プリプロセッサ ディレクティブを使用してオプトインできます。

コンテキストと警告について

警告と注釈を有効にすると、コンパイラが参照型と null 値の許容をどのように捉えるかを制御できます。 すべての型には、次の 3 つの null 値の許容の 1 つがあります。

  • "未指定": 注釈コンテキストが無効になっている場合、すべての参照型が null 許容 "未指定" です。
  • "null 非許容": 注釈なし参照型の C は、注釈コンテキストが有効な場合、"null 非許容" です。
  • "null 許容": 注釈付き参照型の C? は、"null 許容" ですが、注釈コンテキストが無効な場合、警告が発行される可能性があります。 注釈コンテキストが有効になっている場合、var で宣言された変数は "null 許容" です。

null 値の許容に基づいて、警告がコンパイラによって生成されます。

  • "null 非許容" 型は、潜在的な null 値が割り当てられている場合に警告を発生させます。
  • "null 許容" 型は、"null の可能性あり" のときに参照された場合に警告を発生させます。
  • "未指定" 型は、"null の可能性あり" で、警告コンテキストが有効になっているときに逆参照された場合に警告を発生させます。

各変数には、null 値の許容に依存する既定の null 許容状態があります。

  • null 許容変数では、既定の "null 状態" は "null の可能性あり" です。
  • null 非許容変数では、既定の "null 状態" は "null 以外" です。
  • null 許容の未指定変数では、既定の "null 状態" は "null 以外" です。

null 許容参照型を有効にする前、コードベース内のすべての宣言が "null 許容未指定" です。 これは、すべての参照型で、既定の null 状態null 以外 であることを意味するため、重要です。

警告に対処する

プロジェクトで Entity Framework Core を使用する場合は、null 許容参照型の使用に関するガイダンスを参照してください。

移行を開始するときは、警告のみを有効にすることから始める必要があります。 すべての宣言は "null 許容未指定" のままですが、"null 状態" が "null の可能性あり" に変更された後に値を逆参照すると、警告が表示されます。 これらの警告に対処すると、より多くの場所で null 値をチェックすることになり、コードベースの回復性が向上します。 さまざまな状況に固有の手法については、null 許容型の警告を解決する方法に関する記事をご覧ください。

警告に対処し、各ファイルまたはクラスで注釈を有効にしてから、他のコードを続行することができます。 しかしながら、コンテキストが "警告" である間に生成される警告に対処してから、型の注釈を有効にする方が効率的であることが多いです。 そうすることで、すべての型が、最初の警告セットに対処するまで "未指定" です。

型の注釈を有効にする

最初の一連の警告に対処したら、"注釈コンテキスト" を有効にできます。 これにより、参照型が "未指定" から "null 非許容" に変更されます。 var で宣言された変数はすべて "null 非許容" です。 この変更によって、多くの場合、新しい警告が発生します。 コンパイラの警告に対処するための最初の手順は、パラメーターと戻り値の型で ? 注釈を使用して、引数または戻り値が null になる可能性があるときを示すことです。 この作業を行うときの目標は、警告を修正することだけではありません。 より重要な目標は、null 値の可能性があるという意図をコンパイラに理解させることです。

属性で型の注釈を拡張する

変数の null 状態に関する追加情報を表すために、いくつかの属性が追加されました。 API の規則は、すべてのパラメーターと戻り値について、"null 以外" または "null の可能性あり" よりも複雑である可能性があります。 多くの API には、変数を null にできる場合やできない場合のより複雑な規則があります。 このような場合は、属性を使用してそれらの規則を表します。 API のセマンティクスを記述する属性については、null 許容の分析に影響を与える属性に関する記事を参照してください。

次のステップ

注釈を有効にした後ですべての警告に対処したら、プロジェクトの既定のコンテキストを "有効" に設定できます。 null 許容注釈または警告コンテキストの pragma をコードに追加した場合は、それらを削除できます。 時間の経過と共に、新しい警告が表示されることがあります。 警告を導入するコードを記述することができます。 null 許容参照型に対して、ライブラリの依存関係が更新される可能性があります。 これらの更新により、そのライブラリ内の型が null 許容未指定 から null 非許容 または null 許容 に変更されます。

また、これらの概念は、「C# での Null Safety」についての Learn モジュールでも確認できます。