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);
}
從 C# 13 開始,此程式碼會產生編譯器錯誤。
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
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
子句。 方法主體可以由該單行取代:
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();
}
若要修正此警告,請變更傳回型別或移除方法。