C# 警告ウェーブ

C# コンパイラの各リリースでは、新しい警告とエラーが導入される可能性があります。 既存のコードに対して新しい警告が報告される可能性がある場合、それらの警告は "警告ウェーブ" と呼ばれるオプトイン システムで導入されます。 オプトイン システムとは、既存のコードに対する新しい警告は、それらを有効にするアクションを実行しないと表示されないことを意味します。 警告ウェーブは、プロジェクト ファイルの AnalysisLevel 要素を使って有効にします。 <TreatWarningsAsErrors>true</TreatWarningsAsErrors> を指定すると、有効になった警告ウェーブの警告によってエラーが生成されます。 C# 9 で警告ウェーブ 5 の診断が追加されました。 C# 10 で警告ウェーブ 6 の診断が追加されました。 C# 11 で警告ウェーブ 7 の診断が追加されました。 C# 12 で警告ウェーブ 8 の診断が追加されました。

CS9123 - 非同期メソッドでローカルまたはパラメータのアドレスを取得すると、GC ホールを作成できます。

警告ウェーブ 8

& 演算子は、非同期メソッドのパラメータまたはローカル変数では使用しないでください。 次のコードでは CS9123 が生成されます。

public static async Task LogValue()
{
    int x = 1;
    unsafe {
        int* y = &x;
        Console.WriteLine(*y);
    }
    await Task.Delay(1000);
}

CS8981 - 型名には、小文字の ASCII 文字のみが含まれています。

"警告ウェーブ 7"

C# に追加される新しいキーワードは、すべて小文字の ASCII 文字になります。 この警告によって、どの型も将来のキーワードと競合しないようにします。 次のコードでは CS8981 が生成されます。

public class lowercasename
{
}

この警告に対処するには、小文字以外の ASCII 文字 (大文字、数字、アンダースコアなど) を 1 文字以上含むように型の名前を変更します。

CS8826 - 部分メソッドの宣言には、シグネチャの違いがあります。

"警告ウェーブ 6"

この警告は、部分メソッドのシグネチャ間の相違点を報告するときに、不整合を修正します。 部分メソッドのシグネチャによって異なる CLR シグネチャが作成されたとき、コンパイラは常にエラーを報告していました。 現在、シグネチャが構文的に異なる C# である場合、コンパイラは CS8826 を報告します。 次の部分クラスについて考えてみます。

public partial class PartialType
{
    public partial void M1(int x);

    public partial T M2<T>(string s) where T : struct;

    public partial void M3(string s);


    public partial void M4(object o);
    public partial void M5(dynamic o);
    public partial void M6(string? s);
}

次の部分クラスの実装では、CS8626 の例がいくつか生成されます。

public partial class PartialType
{
    // Different parameter names:
    public partial void M1(int y) { }

    // Different type parameter names:
    public partial TResult M2<TResult>(string s) where TResult : struct => default;

    // Relaxed nullability
    public partial void M3(string? s) { }


    // Mixing object and dynamic
    public partial void M4(dynamic o) { }

    // Mixing object and dynamic
    public partial void M5(object o) { }

    // Note: This generates CS8611 (nullability mismatch) not CS8826
    public partial void M6(string s) { }
}

注意

あるメソッドの実装が null 非許容参照型を使用し、他の宣言が null 許容参照型を受け入れる場合、CS8826 の代わりに CS8611 が生成されます。

これらの警告が発生したケースを修正するには、2 つのシグネチャを一致させてください。

CS7023 - 'is' または 'as' 式で静的型が使用されています。

"警告ウェーブ 5"

静的型のインスタンスは作成できないため、is 式と as 式は静的型に対して常に false を返します。 次のコードでは CS7023 が生成されます。

static class StaticClass
{
    public static void Thing() { }
}

void M(object o)
{
    // warning: cannot use a static type in 'is' or 'as'
    if (o is StaticClass)
    {
        Console.WriteLine("Can't happen");
    }
    else
    {
        Console.WriteLine("o is not an instance of a static class");
    }
}

コンパイラがこの警告を報告するのは、この型テストが成功することはないためです。 この警告を修正するには、テストを削除し、テストが成功した場合にのみ実行されるすべてのコードを削除します。 上記の例では、else 句が常に実行されます。 メソッド本体はその 1 行に置き換えることができます。

Console.WriteLine("o is not an instance of a static class");

CS8073 - 式の結果が常に 'false' (または 'true') です。

"警告ウェーブ 5"

struct 型のインスタンスを null と比較する場合、== および != 演算子は常に false (または true) を返します。 次のコードはこの警告を示しています。 Sstructoperator == が定義されている operator != であると想定してください。

class Program
{
    public static void M(S s)
    {
        if (s == null) { } // CS8073: The result of the expression is always 'false'
        if (s != null) { } // CS8073: The result of the expression is always 'true'
    }
}

struct S
{
    public static bool operator ==(S s1, S s2) => s1.Equals(s2);
    public static bool operator !=(S s1, S s2) => !s1.Equals(s2);
    public override bool Equals(object? other)
    {
        // Implementation elided
        return false;
    }
    public override int GetHashCode() => 0;

    // Other details elided...
}

このエラーを修正するには、null チェックと、オブジェクトが null である場合に実行されるコードを削除します。

CS8848 - 優先順位の理由から、こちらで演算子 'from' は使用できません。 かっこを使用して明確にしてください。

"警告ウェーブ 5"

次の例はこの警告を示しています。 演算子の優先順位によって、式は正しくバインドされません。

bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && from c in source select c;
Console.WriteLine(a);

var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..from c in indexes select c];

このエラーを修正するには、クエリ式の周りにかっこを配置します。

bool b = true;
var source = new Src();
b = true;
source = new Src();
var a = b && (from c in source select c);
Console.WriteLine(a);

var indexes = new Src2();
int[] array = { 1, 2, 3, 4, 5, 6, 7 };
var range = array[0..(from c in indexes select c)];

メンバーを完全に代入する必要があります。代入されない変数の使用 (CS8880、CS8881、CS8882、CS8883、CS8884、CS8885、CS8886、CS8887)

"警告ウェーブ 5"

いくつかの警告により、インポートされたアセンブリで宣言された struct 型の限定代入の分析が改善されます。 次の例に示すように、インポートされたアセンブリ内の構造体に参照型のアクセスできないフィールド (通常は private フィールド) が含まれている場合、次の新しい警告すべてが生成されます。

public struct Struct
{
    private string data = String.Empty;
    public Struct() { }
}

次の例は、改善された限定代入の分析から生成される警告を示しています。

  • CS8880: 自動実装プロパティ 'Property' は、制御が呼び出し元に返される前に完全に代入される必要があります。
  • CS8881: フィールド 'field' は、制御が呼び出し元に返される前に完全に代入される必要があります。
  • CS8882: out パラメーター 'parameter' は制御が現在のメソッドを抜ける前に代入される必要があります
  • CS8883: 代入されていない可能性のある自動実装プロパティ 'Property' の使用。
  • CS8884: 代入されていない可能性のあるフィールド 'Field' の使用
  • CS8885: すべてのフィールドが代入されるまで、この 'this' オブジェクトは使用できません。
  • CS8886: 代入されていない out パラメーター 'parameterName' の使用。
  • CS8887: 代入されていないローカル変数 'variableName' の使用
public struct DefiniteAssignmentWarnings
{
    // CS8880
    public Struct Property { get; }
    // CS8881
    private Struct field;

    // CS8882
    public void Method(out Struct s)
    {

    }

    public DefiniteAssignmentWarnings(int dummy)
    {
        // CS8883
        Struct v2 = Property;
        // CS8884
        Struct v3 = field;
        // CS8885:
        DefiniteAssignmentWarnings p2 = this;
    }

    public static void Method2(out Struct s1)
    {
        // CS8886
        var s2 = s1;
        s1 = default;
    }

    public static void UseLocalStruct()
    {
        Struct r1;
        var r2 = r1;
    }
}

これらの警告はすべて、インポートされた構造体を初期化するか、その既定値に代入することで修正できます。

public struct DefiniteAssignmentNoWarnings
{
    // CS8880
    public Struct Property { get; } = default;
    // CS8881
    private Struct field = default;

    // CS8882
    public void Method(out Struct s)
    {
        s = default;
    }

    public DefiniteAssignmentNoWarnings(int dummy)
    {
        // CS8883
        Struct v2 = Property;
        // CS8884
        Struct v3 = field;
        // CS8885:
        DefiniteAssignmentNoWarnings p2 = this;
    }

    public static void Method2(out Struct s1)
    {
        // CS8886
        s1 = default;
        var s2 = s1;
    }

    public static void UseLocalStruct()
    {
        Struct r1 = default;
        var r2 = r1;
    }
}

CS8892 - 同期エントリ ポイント 'method' が見つかったため、メソッドをエントリ ポイントとして使用できません。

"警告ウェーブ 5"

この警告は、有効なエントリ ポイントが複数ある場合 (1 つ以上の同期エントリ ポイントなど) に、すべての非同期エントリ ポイントの候補に対して生成されます。

次の例では CS8892 が生成されます。

public static void Main()
{
    RunProgram();
}

// CS8892
public static async Task Main(string[] args)
{
    await RunProgramAsync();
}

注意

コンパイラは、常に同期エントリ ポイントを使用します。 同期エントリ ポイントが複数ある場合は、コンパイラ エラーが発生します。

この警告を修正するには、非同期エントリ ポイントを削除するか、名前を変更します。

CS8897 - 静的型をパラメーターとして使用することはできません

"警告ウェーブ 5"

インターフェイスのメンバーでは、型が静的クラスであるパラメーターを宣言できません。 次のコードは、CS8897 と CS8898 の両方を示しています。

public static class Utilities
{
    // elided
}

public interface IUtility
{
    // CS8897
    public void SetUtility(Utilities u);

    // CS8898
    public Utilities GetUtility();
}

この警告を修正するには、パラメーターの型を変更するか、メソッドを削除します。

CS8898 - 静的型を戻り値の型として使用することはできません

"警告ウェーブ 5"

インターフェイスのメンバーでは、静的クラスである戻り値の型を宣言できません。 次のコードは、CS8897 と CS8898 の両方を示しています。

public static class Utilities
{
    // elided
}

public interface IUtility
{
    // CS8897
    public void SetUtility(Utilities u);

    // CS8898
    public Utilities GetUtility();
}

この警告を修正するには、戻り値の型を変更するか、メソッドを削除します。