次の方法で共有


null 許容の警告を解決する

Null 許容の警告の目的は、アプリケーション実行時に System.NullReferenceException がスローされる可能性を最小限に抑えることです。 この目標を達成するために、コンパイラは静的分析を使用し、null 参照例外につながる可能性のあるコンストラクトがコードに含まれている場合に警告を発行します。 型の注釈と属性を適用することで、コンパイラにその静的分析のための情報を提供します。 これらの注釈と属性は、型の引数、パラメーター、メンバーの NULL 値の許容を表します。 この記事では、コンパイラが静的分析から生成する null 許容警告に対処するためのさまざまな手法について説明します。 ここで説明する手法は、一般的な C# コード用です。 「Null 許容参照型の処理」にて、Null 許容参照型と Entity Framework Core を処理する方法を確認してください。

null 許容参照型 (演算子 ?! を含む) は、null 許容コンテキストが enable または annotationsに設定されている場合にのみ許可されます。 null 許容コンテキストは、プロジェクト ファイルの Nullablecompiler オプション を使用するか、ソース コードで #nullable プラグマを使用して設定できます。

この記事では、次のコンパイラ警告について説明します。

  • CS8597 - スローされた値が null である可能性があります。
  • CS8598 - 抑制演算子は、このコンテキストでは使用できません
  • CS8600 - Null リテラルまたは Null の可能性がある値を Null 非許容型に変換しています。
  • CS8601 - Null 参照代入の可能性があります。
  • CS8602 - null 参照の可能性があるものの逆参照です。
  • CS8603 - Null 参照戻り値である可能性があります。
  • CS8604 - パラメーターに Null 参照引数がある可能性があります。
  • CS8605 - null の可能性がある値をボックス化解除しています。
  • CS8607 - [NotNull] または [DisallowNull]としてマークされた型に対して、Null の可能性がある値を使用することはできない
  • CS8608 - 型における参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8609 - 戻り値の型における参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8610 - 型パラメーターにおける参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8611 - 型パラメーターにおける参照型の Null 許容性が、部分メソッド宣言と一致しません。
  • CS8612 - 型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8613 - 戻り値の型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8614 - パラメーターの型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8615 - 型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8616 - 戻り値の型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8617 - パラメーターの型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8618 - null 非許容の変数には、コンストラクターの終了時に null 以外の値が入っていなければなりません。Null 許容として宣言することをご検討ください。
  • CS8619 - 値における参照型の Null 許容性が、対象の型と一致しません。
  • CS8620 - 参照型の NULL 値の許容の違いにより、パラメーターに引数を使用できません。
  • CS8621 - 戻り値の型における参照型の NULL 値の許容が、対象のデリゲートと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8622 - パラメーターの型における参照型の NULL 値の許容が、対象のデリゲートと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8623 - System.Runtime.CompilerServices.NullableAttributeの明示的な適用は許可されていません。
  • CS8624 - 参照型の NULL 値の許容の違いにより、引数を出力として使用することはできません。
  • CS8625 - null リテラルを null 非許容参照型に変換できません。
  • CS8628 - オブジェクトの作成で null 許容参照型を使用できません。
  • CS8629 - Null 許容値型は Null になる場合があります。
  • CS8631 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が制約型と一致しません。
  • CS8632 - null 許容参照型の注釈は、#nullable 注釈コンテキスト内のコードでのみ使用する必要があります。
  • CS8633 - メソッドの型パラメーターに対する制約の Null 許容性が、インターフェイス メソッドの型パラメーターに対する制約と一致しません。明示的なインターフェイスの実装を使用することをお勧めします。
  • CS8634 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が 'class' 制約と一致しません。
  • CS8636 - /nullableのオプションが無効です。は、disableenablewarnings、またはannotationsである必要があります
  • CS8637 - 予期される enabledisable、または restore
  • CS8639 - null 許容参照型では typeof 演算子を使用できません
  • CS8643 - 明示的なインターフェイス指定子内の参照型の Null 許容性が、型によって実装されているインターフェイスと一致しません。
  • CS8644 - 型はインターフェイス メンバーを実装しません。基本型で実装されているインターフェイス内の参照型の Null 許容性が一致しません。
  • CS8645 - メンバーは既に型のインターフェイス リストに存在しますが、参照型の Null 許容性が異なっています。
  • CS8655 - switch 式が一部の null 入力を処理しません (すべてを網羅していません)。
  • CS8667 - 部分メソッド宣言には、型パラメーターの制約に NULL 値の許容の矛盾があります。
  • CS8670 - オブジェクトまたはコレクション初期化子が、null メンバーの可能性があるものを逆参照しています。
  • CS8714 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が 'notnull' 制約と一致しません。
  • CS8762 - 終了時にパラメーターには null 以外の値が含まれている必要があります。
  • CS8763 - [DoesNotReturn] とマークされたメソッドは戻ることができません。
  • CS8764 - 戻り値の型の NULL 値の許容が、オーバーライドされたメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8765 - パラメーターの型の NULL 値の許容が、オーバーライドされたメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8766 - 戻り値の型における参照型の NULL 値の許容が、暗黙的に実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8767 - パラメーターの型における参照型の NULL 値の許容が、暗黙的に実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8768 - 戻り値の型における参照型の NULL 値の許容が、実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8769 - パラメーターの型における参照型の NULL 値の許容が、実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8770 - メソッドには、実装またはオーバーライドされたメンバーに一致する [DoesNotReturn] 注釈がありません。
  • CS8774 - 終了時にメンバーには null 以外の値が含まれている必要があります。
  • CS8776 - この属性ではメンバーを使用できません。
  • CS8775 - 終了時にメンバーには null 以外の値が含まれている必要があります。
  • CS8777 - 終了時にパラメーターには null 以外の値が含まれている必要があります。
  • CS8819 - 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。
  • CS8824 - パラメーターが null 以外であるため、パラメーターには、終了時に null 以外の値が含まれている必要があります。
  • CS8825 - パラメーターが null 以外であるため、戻り値は null 以外でなければなりません。
  • CS8847 - 一部の null 入力が switch 式で処理されません (すべてが網羅されてはいません)。ただし、'when' 句を含むパターンがこの値と一致する可能性があります。

静的分析では、特定のシナリオでメソッドがアクセスされる順序、およびメソッドが例外をスローせずに正常に完了したかどうかについて、常に推測できるわけではありません。 既知の落とし穴については、「既知の 落とし穴 」セクションで説明されています。

次の 5 つの手法のいずれかを使用して、ほぼすべての警告に対処します。

  • null 許容コンテキストの設定。
  • 必要な null チェックを追加する。
  • ? または ! の null 許容注釈を追加または削除します。
  • null セマンティクスを記述する属性を追加する。
  • 変数を正しく初期化する。

null 許容参照型を初めて使用する場合、 null 許容参照型の概要は、null 許容参照型 が解決する内容と、コード内で発生する可能性のある間違いに対する警告を提供するしくみの背景を提供します。 既存のプロジェクトで null 許容参照型を 有効にする方法の詳細については、null 許容参照型への移行に関するガイダンスを確認することもできます。

null許容型のコンテキストを設定する

次の警告は、null 許容コンテキストを正しく設定していないことを示しています。

  • CS8632 - null 許容参照型の注釈は、#nullable 注釈コンテキスト内のコードでのみ使用する必要があります。
  • CS8636 - /nullableのオプションが無効です。は、disableenablewarnings、またはannotationsである必要があります
  • CS8637 - 予期される enabledisable、または restore

null 許容コンテキストを正しく設定するには、次の 2 つのオプションがあります。

  1. プロジェクト レベルの構成: <Nullable> 要素をプロジェクト ファイルに追加します。

    <PropertyGroup>
     <Nullable>enable</Nullable>
    </PropertyGroup>
    
  2. ファイル レベルの構成: ソース コードでプリプロセッサ ディレクティブ #nullable 使用します。

    #nullable enable
    

nullable コンテキストには、さまざまな側面を制御する 2 つの独立したフラグがあります。

  • 注釈フラグ: ? を使用して null 許容参照型を宣言し、 ! を使用して個々の警告を抑制できるかどうかを制御します。
  • 警告フラグ: コンパイラが null 許容警告を出力するかどうかを制御します

null 許容コンテキストと移行戦略の詳細については、次を参照してください。

不適切な注釈構文

これらのエラーと警告は、 ! または ? 注釈の使用が正しくされていないことを示しています。

  • CS8598 - 抑制演算子は、このコンテキストでは使用できません
  • CS8623 - System.Runtime.CompilerServices.NullableAttributeの明示的な適用は許可されていません。
  • CS8628 - オブジェクトの作成で null 許容参照型を使用できません。
  • CS8639 - null 許容参照型では typeof 演算子を使用できません

宣言内の ? 注釈は、変数が null である可能性があることを示します。 別のランタイムの種類を示すわけではありません。 次の宣言はどちらも同じランタイム型です。

string s1 = "a string";
string? s2 = "another string";

?は、null 値に対する期待に関するコンパイラへのヒントです。

式の ! 注釈は、式が安全であることがわかっており、null でないと見なされることを示します。

  • コード内の System.Runtime.CompilerServices.NullableAttribute ではなく、これらの注釈を使用する必要があります。
  • ?は型ではなく注釈であるため、typeof式やnew式では使用できません。
  • !演算子は、変数式またはメソッド グループに適用できません。
  • !演算子は、obj.Field!.Method()などのメンバー アクセス演算子の左側には適用できません。

null の逆参照の可能性

この一連の警告によって、null-statemaybe-null の変数を逆参照していると警告されます。 これらの警告は次のとおりです。

  • CS8602 - null 参照の可能性があるものの逆参照です。
  • CS8670 - オブジェクトまたはコレクション初期化子が、null メンバーの可能性があるものを逆参照しています。

次のコードは、上記の各警告の 1 つの例を示しています。

class Container
{
    public List<string>? States { get; set; }
}

internal void PossibleDereferenceNullExamples(string? message)
{
    Console.WriteLine(message.Length); // CS8602

    var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}

前の例で警告が出るのは、ContainercStates プロパティに null 値を持つ可能性があるためです。 null である可能性があるコレクションに新しい状態を割り当てると、警告が発生します。

これらの警告を削除するには、変数を逆参照する前にその変数の null-statenot-null に変更するためにコードを追加する必要があります。 コレクション初期化子の警告は、見つけにくい場合があります。 初期化子で要素を追加するときに、コレクションが maybe-null であることがコンパイラによって検出されます。

多くの場合、変数を逆参照する前に変数が null でないこと確認することで、これらの警告を修正できます。 message パラメーターを逆参照する前に null チェックを追加する次の例を考えてみましょう。

void WriteMessageLength(string? message)
{
    if (message is not null)
    {
        Console.WriteLine(message.Length);
    }
    
}

次の例では、States のバッキング ストレージを初期化し、set アクセサーを削除します。 クラスのコンシューマーはコレクションの内容を変更でき、コレクションのストレージは決して null にはなりません。

class Container
{
    public List<string> States { get; } = new();
}

これらの警告が表示される他のインスタンスは、擬陽性である可能性があります。 null をテストするプライベート ユーティリティ メソッドがある場合があります。 そのメソッドによって null チェックが提供されることは、コンパイラでは判断できません。 プライベート ユーティリティ メソッド IsNotNull を使用する次の例を考えてみましょう。

public void WriteMessage(string? message)
{
    if (IsNotNull(message))
        Console.WriteLine(message.Length);
}

静的分析によってmessagenull可能性があると判断されるため、プロパティ message.Lengthを記述するときに null を逆参照している可能性があることをコンパイラから警告します。 IsNotNullは null チェックを提供し、true を返すとき、messagenull 状態null でないことを知っています。 コンパイラにそれらの事実を伝える必要があります。 1 つは、null 免除演算子 ! を使用する方法です。 次のコードと一致するように、WriteLine ステートメントを変更できます。

Console.WriteLine(message!.Length);

null 免除演算子を使用すると、その式が ! が適用されていない場合は maybe-null であったとしても、not-null になります。 この例では、IsNotNull のシグネチャに属性を追加する解決策のほうが適切です。

private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;

メソッドで true が返されるときは、obj パラメーターに使用されている引数は not-null であるという情報が、System.Diagnostics.CodeAnalysis.NotNullWhenAttribute によってコンパイラに伝えられます。 メソッドで false が返されるとき、その引数にはそのメソッドが呼びされた前と同じ null-state があります。

ヒント

メソッドやプロパティが null-state に及ぼす影響を記述するために使用できる、一連の豊富な属性が用意されています。 それらの詳細については、Null 許容静的分析属性に関する言語参照の記事で確認できます。

maybe-null の変数の逆参照に関する警告を修正することには、次の 3 つのいずれかの手法が関与します。

  • 欠けている null チェックを追加する。
  • API に null 分析属性を追加して、コンパイラの null-state の静的分析に影響を与える。 メソッドを呼び出した後に戻り値または引数が maybe-null または not-null になるときが、これらの属性によってコンパイラに伝えられます。
  • null 許容演算子 ! を式に適用し、状態を 強制的に not-null にします。

Null 非許容参照に null が代入されている可能性

この一連の警告は、null 非許容の型の変数を、null-statemaybe-null の式に代入しようとしていることを警告します。 これらの警告は次のとおりです。

  • CS8597 - スローされた値が null である可能性があります。
  • CS8600 - Null リテラルまたは Null の可能性がある値を Null 非許容型に変換しています。
  • CS8601 - Null 参照代入の可能性があります。
  • CS8603 - Null 参照戻り値である可能性があります。
  • CS8604 - パラメーターに Null 参照引数がある可能性があります。
  • CS8605 - null の可能性がある値をボックス化解除しています。
  • CS8625 - null リテラルを null 非許容参照型に変換できません。
  • CS8629 - Null 許容値型は Null になる場合があります。

Null 非許容の変数に maybe-null の式を代入しようとすると、コンパイラからこれらの警告が発せられます。 例えば次が挙げられます。

string? TryGetMessage(int id) => "";

string msg = TryGetMessage(42);  // Possible null assignment.

さまざまな警告は、代入、ボックス化解除の割り当て、return ステートメント、メソッドの引数、throw 式など、コードに関する詳細を提供することを示しています。

これらの警告に対処するために、3 つのいずれかのアクションを実行できます。 1 つは、? 注釈を追加して変数を Null 許容参照型にする方法です。 この変更により、他の警告が発生する可能性があります。 変数を Null 非許容参照から Null 許容参照に変更することで、その既定の null-statenot-null から maybe-null に変わります。 コンパイラの静的分析では、もしかしたら null かもしれない変数を逆参照する可能性があるインスタンスが見つかります。

その他のアクションによって、代入の右側が not-null であるということがコンパイラに伝えられます。 次の例に示すように、右側の式には代入の前に null チェックを行うことができました。

string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";

前の例は、メソッドの戻り値の代入を示します。 メソッド (またはプロパティ) に注釈を付けて、メソッドが null 以外の値を返すタイミングを示します。 多くの場合、入力引数が not-null のときに戻り値が not-null であることが System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute によって特定されます。 もう 1 つは、null 免除演算子 ! を右側に追加する方法です。

string msg = TryGetMessage(42)!;

maybe-null 式を not-null 変数に代入することに関する警告を修正することには、次の 4 つのいずれかの手法が関与します。

  • 代入の左側を Null 許容型に変更する。 このアクションでは、その変数を逆参照すると、新しい警告が発生する可能性があります。
  • 代入の前に null チェックを指定する。
  • 代入の右側を生成する API に注釈を付ける。
  • null 免除演算子を代入の右側に追加する。

初期化されていない Null 非許容参照

この一連の警告は、null 非許容の型の変数を、null-statemaybe-null の式に代入しようとしていることを警告します。 これらの警告は次のとおりです。

  • CS8618 - null 非許容の変数には、コンストラクターの終了時に null 以外の値が入っていなければなりません。Null 許容として宣言することをご検討ください。
  • CS8762 - 終了時にパラメーターには null 以外の値が含まれている必要があります。

例として、次のクラスについて考えてみましょう。

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

FirstNameLastName はどちらも初期化が保証されていません。 このコードが新しい場合は、パブリック インターフェイスの変更を検討してください。 上記の例は、次のように更新できます。

public class Person
{
    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

名前を設定する前に Person オブジェクトを作成する必要がある場合は、既定の null 以外の値を使用してプロパティを初期化できます。

public class Person
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

もう 1 つの方法は、これらのメンバーを null 許容参照型に変更することです。 名前に null が許可される必要がある場合は、Person クラスを次のように定義できます。

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

既存のコードでは、これらのメンバーの null セマンティクスについてコンパイラに通知するために、他の変更が必要になる場合があります。 複数のコンストラクターがあり、クラスには 1 つ以上のメンバーを初期化するプライベート ヘルパー メソッドがあります。 初期化コードを 1 つのコンストラクターに移動し、すべてのコンストラクターから共通の初期化コードを含むものを呼び出すようにすることができます。 または、System.Diagnostics.CodeAnalysis.MemberNotNullAttribute 属性と System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute 属性を使用できます。 これらの属性は、メソッドが戻った後にメンバーが null ではないこと をコンパイラに通知します。 次のコードは、それぞれの例を示しています。 Person クラスでは、他のすべてのコンストラクターによって呼び出される共通のコンストラクターを使用しています。 Student クラスには、System.Diagnostics.CodeAnalysis.MemberNotNullAttribute 属性で注釈付けされたヘルパー メソッドがあります。


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

最後に、null 免除演算子を使用して、メンバーが他のコードで初期化されていることを示すことができます。 別の例として、Entity Framework Core モデルを表す次のクラスについて考えてみてください。

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

DbSet プロパティは null! に初期化されます。 プロパティが not-null 値に設定されたことがコンパイラに伝えられます。 実際、ベースの DbContext によってそのセットの初期化が実行されます。 コンパイラの静的分析では、それを拾いません。 null 許容参照型と Entity Framework Core の処理の詳細については、「EF Core での Null 許容参照型の処理」の記事を参照してください。

Null 非許容メンバーの初期化に関する警告を修正することには、次の 4 つのいずれかの手法が関与します。

  • コンストラクターまたはフィールド初期化子を変更し、すべての Null 非許容メンバーが初期化されるようにする。
  • 1 つ以上のメンバーを Null 許容型に変更する。
  • ヘルパー メソッドに注釈を付け、どのメンバーが代入されているかを示す。
  • null! に初期化子を追加して、そのメンバーが他のコードで初期化されていることを示す。

NULL 値の許容の宣言の不一致

多くの警告では、メソッド、デリゲート、型パラメーターのシグネチャ間の NULL 値の許容不一致を示します。

  • CS8608 - 型における参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8609 - 戻り値の型における参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8610 - 型パラメーターにおける参照型の Null 許容性が、オーバーライドされるメンバーと一致しません。
  • CS8611 - 型パラメーターにおける参照型の Null 許容性が、部分メソッド宣言と一致しません。
  • CS8612 - 型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8613 - 戻り値の型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8614 - パラメーターの型における参照型の Null 許容性が、暗黙的に実装されるメンバーと一致しません。
  • CS8615 - 型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8616 - 戻り値の型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8617 - パラメーターの型における参照型の Null 許容性が、実装されるメンバーと一致しません。
  • CS8619 - 値における参照型の Null 許容性が、対象の型と一致しません。
  • CS8620 - 参照型の NULL 値の許容の違いにより、パラメーターに引数を使用できません。
  • CS8621 - 戻り値の型における参照型の NULL 値の許容が、対象のデリゲートと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8622 - パラメーターの型における参照型の NULL 値の許容が、対象のデリゲートと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8624 - 参照型の NULL 値の許容の違いにより、引数を出力として使用することはできません。
  • CS8631 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が制約型と一致しません。
  • CS8633 - メソッドの型パラメーターに対する制約の Null 許容性が、インターフェイス メソッドの型パラメーターに対する制約と一致しません。明示的なインターフェイスの実装を使用することをお勧めします。
  • CS8634 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が 'class' 制約と一致しません。
  • CS8643 - 明示的なインターフェイス指定子内の参照型の Null 許容性が、型によって実装されているインターフェイスと一致しません。
  • CS8644 - 型はインターフェイス メンバーを実装しません。基本型で実装されているインターフェイス内の参照型の Null 許容性が一致しません。
  • CS8645 - メンバーは既に型のインターフェイス リストに存在しますが、参照型の Null 許容性が異なっています。
  • CS8667 - 部分メソッド宣言には、型パラメーターの制約に NULL 値の許容の矛盾があります。
  • CS8714 - この型を、ジェネリック型またはメソッド内で型パラメーターとして使用することはできません。型引数の Null 許容性が 'notnull' 制約と一致しません。
  • CS8764 - 戻り値の型の NULL 値の許容が、オーバーライドされたメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8765 - パラメーターの型の NULL 値の許容が、オーバーライドされたメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8766 - 戻り値の型における参照型の NULL 値の許容が、暗黙的に実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8767 - パラメーターの型における参照型の NULL 値の許容が、暗黙的に実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8768 - 戻り値の型における参照型の NULL 値の許容が、実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8769 - パラメーターの型における参照型の NULL 値の許容が、実装されるメンバーと一致しません。おそらく、NULL 値の許容の属性が原因です。
  • CS8819 - 戻り値の型における参照型の Null 値の許容が、部分メソッド宣言と一致しません。

次のコードは CS8764 を示しています。

public class B
{
    public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
    public override string? GetMessage(string? id) => default;
}

前の例は、ベース クラス内の virtual メソッドと、NULL 値の許容が異なる override を示します。 基本クラスでは Null 非許容文字列を返しますが、派生クラスでは Null 許容文字列を返します。 stringstring? が逆の場合は、派生クラスのほうがより制約があるため、許可されます。 同様に、パラメーターの宣言が一致する必要があります。 オーバーライド メソッドのパラメーターでは、基本クラスで許可されない場合でも null が許可されます。

他の状況では、これらの警告が生成される可能性があります。 インターフェイス メソッドの宣言とそのメソッドの実装が一致していません。 デリゲート型とそのデリゲートの式が異なる場合があります。 型パラメーターと型引数は null 値の許容が異なります。

これらの警告を修正するには、適切な宣言を更新します。

コードが属性宣言と一致しない

前のセクションでは、 Null 許容の静的分析に属性 を使用して、コードの null セマンティクスについてコンパイラに通知する方法について説明しました。 コードがその属性の約束事に従わない場合、コンパイラから警告が発生します。

  • CS8607 - [NotNull] または [DisallowNull] としてマークされた型に対して、Null の可能性がある値を使用することはできない
  • CS8763 - [DoesNotReturn] とマークされたメソッドは戻ることができません。
  • CS8770 - [DoesNotReturn] メソッドには、実装またはオーバーライドされたメンバーに一致する 注釈がありません。
  • CS8774 - 終了時にメンバーには null 以外の値が含まれている必要があります。
  • CS8775 - 終了時にメンバーには null 以外の値が含まれている必要があります。
  • CS8776 - この属性ではメンバーを使用できません。
  • CS8777 - 終了時にパラメーターには null 以外の値が含まれている必要があります。
  • CS8824 - パラメーターが null 以外であるため、パラメーターには、終了時に null 以外の値が含まれている必要があります。
  • CS8825 - パラメーターが null 以外であるため、戻り値は null 以外でなければなりません。

次のメソッドがあるとします。

public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
    message = null;
    return true;

}

message パラメーターに null が代入され、"かつ" メソッドで true が返されるため、コンパイラで警告が発生します。 NotNullWhen 属性によって、それは発生しないはずであると指摘されます。

これらの警告に対処するには、コードを更新して、適用される属性の期待値と一致するようにします。 属性またはアルゴリズムを変更できます。

網羅的な switch 式

switch 式は "網羅的" である必要があります。つまり、すべての入力値が処理される必要があります。 null 非許容の参照型の場合でも、null 値が考慮される必要があります。 null 値が処理されない場合、コンパイラの警告が発行されます。

  • CS8655 - switch 式が一部の null 入力を処理しません (すべてを網羅していません)。
  • CS8847 - 一部の null 入力が switch 式で処理されません (すべてが網羅されてはいません)。ただし、'when' 句を含むパターンがこの値と一致する可能性があります。

次のサンプル コードは、この条件を示しています。

int AsScale(string status) =>
    status switch
    {
        "Red" => 0,
        "Yellow" => 5,
        "Green" => 10,
        { } => -1
    };

入力式は string ですが、string? ではありません。 やはりコンパイラでこの警告が生成されます。 { } パターンは null 以外のすべての値を処理しますが、null に一致しません。 これらのエラーに対処するには、明示的な null ケースを追加するか、{ }_ (破棄) パターンに置き換えます。 破棄パターンは、他の値に加えて null と一致します。