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 字元,例如大寫字元、數位或底線,以解決此問題。

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 的參考型別,則會產生 CS8611 而不是 CS8826。

若要修正這些警告的任何執行個體,請確定兩個簽章相符。

CS7023 - 靜態類型用於 'is' 或 'as' 運算式中。

警告波 5

isas 運算式一律會為靜態類型傳回 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 子句。 方法主體可以由該單行取代:

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

CS8073 - 運算式的結果一律為 'false' (或 'true')。

警告波 5

比較 struct 類型和 null 時,==!= 運算子一律會傳回 false (或 true)。 下列程式碼可示範這項警告。 假設 S 是定義 operator ==operator !=struct

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:使用未指派的輸出參數 'parameterName'。
  • CS8887:使用未指派的區域變數 'name'
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

當您有多個有效的進入點時,所有非同步進入點候選項目都會產生這個警告,包括一或多個同步進入點。

下列範例會產生 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();
}

若要修正此警告,請變更傳回型別或移除方法。