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. Po określeniu <TreatWarningsAsErrors>true</TreatWarningsAsErrors>, włączone ostrzeżenia dotyczące fali generują błędy. Dodano diagnostykę z falą ostrzegawczą 5 w języku C# 9. Dodano diagnostyki ostrzeżeń fali 6 w języku C# 10. Dodano diagnostykę z falą ostrzegawczą 7 w języku C# 11. Dodano diagnostykę fali ostrzeżeń 8 w języku C# 12. Dodano diagnostykę z falą ostrzegawczą 9 w języku C# 13. Dodano diagnostykę fali ostrzeżeń 10 w C# 14.

Począwszy od zestawu .NET 7 SDK (C# 11), system kompilacji ustawia fale ostrzegawcze z następującymi regułami:

  • AnalysisLevel śledzi bieżący TFM, jeśli nie jest określony
  • Właściwość AnalysisLevel jest ustawiona na najnowszą, jeśli bieżący TFM jest "najnowszym" TFM (zdefiniowanym przez właściwość, którą musimy zaktualizować).
  • WarningLevel powinien śledzić bieżący TFM, jeśli nie zostanie określony
  • WarningLevel nie powinien zastępować wartości podanej przez użytkownika
  • Wartość WarningLevel powinna być ustawiona na 4, jeśli projekt jest projektem .NET Framework

W przypadku zestawów SDK wcześniejszych niż .NET 7 funkcja AnalysisLevel zawsze zastępuje wartość WarningLevel.

CS9265 — pole nigdy nie jest przypisywane jako ref i zawsze będzie miało wartość domyślną

Fala ostrzegawcza 10

ref Pole w obiekcieref struct, do którego nigdy nie przypisano odwołania, zawsze ma wartość domyślną, którą jest referencja o wartości null. Poniższy kod tworzy CS9265:

ref struct Container
{
    // CS9265: Field 'value' is never ref-assigned to,
    // and will always have its default value (null reference)
    public ref int value;
}

Aby rozwiązać to ostrzeżenie, można przypisać pole przez referencję w inicjatorze pola lub we wszystkich ścieżkach kodu konstruktora. Alternatywnie usuń ref modyfikator z deklaracji pola, jeśli pole nie musi być odwołaniem.

CS9123 — operator "&" nie powinien być używany w parametrach ani zmiennych lokalnych w metodach asynchronicznych

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);
}

CS8981 — nazwa typu zawiera tylko małe litery znaków ascii. Takie nazwy mogą stać się zarezerwowane dla języka.

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 sygnaturze.

Fala ostrzegawcza 6

To ostrzeżenie poprawia pewne niespójności w raportowaniu różnic między częściowymi sygnaturami metod. Kompilator zawsze zgłaszał błąd, gdy sygnatury metody częściowej utworzyły różne sygnatury CLR. Teraz kompilator raportuje CS8826, gdy sygnatury 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 non-null, gdy inna deklaracja dopuszcza typy referencyjne dopuszczające wartości null, generowany jest CS8611 zamiast CS8826.

Aby naprawić dowolne wystąpienie tych ostrzeżeń, upewnij się, że dwa podpisy są zgodne.

CS7023 — drugi operand operatora "is" lub "as" nie może być typem statycznym

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 "wartość", ponieważ wartość typu "type" nigdy nie jest równa wartości "null" typu "type"

Fala ostrzegawcza 5

Operatory == i != zawsze zwracają false (lub true) w porównaniu instancji typu struct do null. Poniższy kod demonstruje to ostrzeżenie. Załóżmy, że S jest struct, który definiuje operator == oraz 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 z powodu pierwszeństwa. 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 jednoznacznego przypisania.

  • CS8880: Właściwość zaimplementowana automatycznie musi być w pełni przypisana przed zwróceniem kontrolki do obiektu wywołującego. Rozważ aktualizację do wersji językowej "version", aby automatycznie ustawić właściwość .
  • CS8881: Pole "pole" musi być w pełni przypisane przed zwróceniem sterowania do wywołującego. Rozważ zaktualizowanie do wersji językowej "version", aby automatycznie ustawić pole jako domyślne.
  • CS8882: Parametr out 'parametr' musi zostać przypisany, zanim opuszczona zostanie bieżąca metoda.
  • 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" zanim wszystkie jego pola zostaną przypisane. Rozważ aktualizację do wersji językowej "version" w celu automatycznego ustawienia nieprzypisanych pól.
  • CS8886: Użyj nieprzypisanego parametru "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ę.