Fale ostrzegawcze języka C#
Nowe ostrzeżenia i błędy można wprowadzić w każdej wersji kompilatora języka C#. Gdy nowe ostrzeżenia mogą być zgłaszane w istniejącym kodzie, ostrzeżenia te są wprowadzane w systemie zgody nazywanym falą ostrzegawczą. System zgody oznacza, że nie powinny być wyświetlane nowe ostrzeżenia dotyczące istniejącego kodu bez podejmowania działań w celu ich włączenia. Fale ostrzegawcze są włączone przy użyciu elementu AnalysisLevel w pliku projektu. Po <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
określeniu włączone ostrzeżenia o fali ostrzegawczej generują błędy. Dodano diagnostykę z falą ostrzegawczą 5 w języku C# 9. Dodano diagnostykę z falą ostrzegawczą 6 w języku C# 10. Dodano diagnostykę z falą ostrzegawczą 7 w języku C# 11. Dodano diagnostykę z falą ostrzegawczą 8 w języku C# 12.
CS9123 — pobieranie adresu lokalnego lub parametru w metodzie asynchronicznej może utworzyć otwór GC.
Fala ostrzegawcza 8
Operator &
nie powinien być używany w parametrach ani zmiennych lokalnych w metodach asynchronicznych.
Poniższy kod tworzy CS9123:
public static async Task LogValue()
{
int x = 1;
unsafe {
int* y = &x;
Console.WriteLine(*y);
}
await Task.Delay(1000);
}
Począwszy od języka C# 13, ten kod generuje błąd kompilatora.
CS8981 — nazwa typu zawiera tylko małe litery znaków ascii.
Fala ostrzegawcza 7
Wszystkie nowe słowa kluczowe dodane dla języka C# będą mieć małe litery znaków ASCII. To ostrzeżenie gwarantuje, że żaden z typów nie powoduje konfliktu z przyszłymi słowami kluczowymi. Poniższy kod tworzy CS8981:
public class lowercasename
{
}
To ostrzeżenie można rozwiązać, zmieniając nazwę typu, aby uwzględnić co najmniej jeden znak ASCII, taki jak wielkie litery, cyfra lub podkreślenie.
CS8826 — deklaracje metody częściowej mają różnice w podpisie.
Fala ostrzegawcza 6
To ostrzeżenie poprawia pewne niespójności w raportowaniu różnic między podpisami metody częściowej. Kompilator zawsze zgłaszał błąd, gdy podpisy metody częściowej utworzyły różne podpisy CLR. Teraz kompilator raportuje CS8826, gdy podpisy są składniowo różne w języku C#. Rozważmy następującą klasę częściową:
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);
}
Następująca implementacja klasy częściowej generuje kilka przykładów 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) { }
}
Uwaga
Jeśli implementacja metody używa typu odwołania innego niż null, gdy inna deklaracja akceptuje typy referencyjne dopuszczane wartości null, cs8611 jest generowany zamiast CS8826.
Aby naprawić dowolne wystąpienie tych ostrzeżeń, upewnij się, że dwa podpisy są zgodne.
CS7023 — typ statyczny jest używany w wyrażeniu "is" lub "as".
Fala ostrzegawcza 5
Wyrażenia is
i as
zawsze zwracają false
dla typu statycznego, ponieważ nie można tworzyć wystąpień typu statycznego. Poniższy kod tworzy 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");
}
}
Kompilator zgłasza to ostrzeżenie, ponieważ test typu nigdy nie powiedzie się. Aby poprawić to ostrzeżenie, usuń test i usuń dowolny kod wykonany tylko wtedy, gdy test zakończył się pomyślnie. W poprzednim przykładzie klauzula else
jest zawsze wykonywana. Tę treść metody można zastąpić pojedynczym wierszem:
Console.WriteLine("o is not an instance of a static class");
CS8073 — wynik wyrażenia jest zawsze "false" (lub "true").
Fala ostrzegawcza 5
Operatory ==
i !=
zawsze zwracają false
wartość (lub true
) podczas porównywania wystąpienia struct
typu z null
. Poniższy kod demonstruje to ostrzeżenie. ZałóżmyS
, że definiuje operator ==
struct
element i 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...
}
Aby naprawić ten błąd, usuń sprawdzanie wartości null i kod, który będzie wykonywany, jeśli obiekt ma wartość null
.
CS8848 — operator "from" nie może być używany tutaj ze względu na pierwszeństwo. Użyj nawiasów, aby uściślić.
Fala ostrzegawcza 5
W poniższych przykładach pokazano to ostrzeżenie. Wyrażenie jest niepoprawnie powiązane ze względu na pierwszeństwo operatorów.
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];
Aby naprawić ten błąd, umieść nawiasy wokół wyrażenia zapytania:
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)];
Członkowie muszą być w pełni przypisani. Użycie nieprzypisanej zmiennej (CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)
Fala ostrzegawcza 5
Kilka ostrzeżeń poprawia określoną analizę przypisania dla struct
typów zadeklarowanych w importowanych zestawach. Wszystkie te nowe ostrzeżenia są generowane, gdy struktura w zaimportowanym zestawie zawiera niedostępne pole (zwykle private
pole) typu odwołania, jak pokazano w poniższym przykładzie:
public struct Struct
{
private string data = String.Empty;
public Struct() { }
}
W poniższych przykładach pokazano ostrzeżenia wygenerowane na podstawie ulepszonej analizy określonego przypisania:
- CS8880: Właściwość zaimplementowana automatycznie musi być w pełni przypisana przed zwróceniem kontrolki do obiektu wywołującego.
- CS8881: Pole "pole" musi być w pełni przypisane przed zwróceniem kontrolki do wywołującego.
- CS8882: parametr wyjściowy "parametr" musi zostać przypisany do kontrolki przed opuszczeniem bieżącej metody.
- CS8883: Użycie prawdopodobnie nieprzypisanej automatycznie zaimplementowanej właściwości "Property".
- CS8884: Użycie prawdopodobnie nieprzypisanego pola "Pole"
- CS8885: Nie można użyć obiektu "this" przed przypisaniem wszystkich pól.
- CS8886: Użycie nieprzypisanego parametru wyjściowego "parameterName".
- CS8887: Używanie nieprzypisanej zmiennej lokalnej "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;
}
}
Możesz naprawić dowolne z tych ostrzeżeń, inicjując lub przypisując zaimportowaną strukturę do jej wartości domyślnej:
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 — metoda nie będzie używana jako punkt wejścia, ponieważ znaleziono synchroniczny punkt wejścia "method".
Fala ostrzegawcza 5
To ostrzeżenie jest generowane dla wszystkich kandydatów do punktu wejścia asynchronicznego, gdy masz wiele prawidłowych punktów wejścia, w tym co najmniej jeden synchroniczny punkt wejścia.
Poniższy przykład generuje CS8892:
public static void Main()
{
RunProgram();
}
// CS8892
public static async Task Main(string[] args)
{
await RunProgramAsync();
}
Uwaga
Kompilator zawsze używa synchronicznego punktu wejścia. W przypadku wystąpienia wielu synchronicznych punktów wejścia występuje błąd kompilatora.
Aby naprawić to ostrzeżenie, usuń lub zmień nazwę punktu wejścia asynchronicznego.
CS8897 — nie można używać typów statycznych jako parametrów
Fala ostrzegawcza 5
Elementy członkowskie interfejsu nie mogą deklarować parametrów, których typ jest klasą statyczną. Poniższy kod demonstruje zarówno CS8897, jak i CS8898:
public static class Utilities
{
// elided
}
public interface IUtility
{
// CS8897
public void SetUtility(Utilities u);
// CS8898
public Utilities GetUtility();
}
Aby naprawić to ostrzeżenie, zmień typ parametru lub usuń metodę.
CS8898 — typy statyczne nie mogą być używane jako typy zwracane
Fala ostrzegawcza 5
Elementy członkowskie interfejsu nie mogą zadeklarować typu zwracanego, który jest klasą statyczną. Poniższy kod demonstruje zarówno CS8897, jak i CS8898:
public static class Utilities
{
// elided
}
public interface IUtility
{
// CS8897
public void SetUtility(Utilities u);
// CS8898
public Utilities GetUtility();
}
Aby naprawić to ostrzeżenie, zmień typ zwracany lub usuń metodę.