C# Figyelmeztető hullámok

A C#-fordító minden egyes kiadásában új figyelmeztetések és hibák jelennek meg. Ha új figyelmeztetések jelenthetők meg a meglévő kódon, ezeket a figyelmeztetéseket egy figyelmeztető hullámnak nevezett opt-in rendszerben vezetik be. A bejelentkezési rendszer azt jelenti, hogy nem szabad új figyelmeztetéseket látnia a meglévő kódon anélkül, hogy lépéseket kellene tennie az engedélyezésük érdekében. Ha meg van adva a <TreatWarningsAsErrors>true</TreatWarningsAsErrors>, az engedélyezett figyelmeztető hullámok hibákat okoznak. Az 5. figyelmeztető hullám diagnosztikái a C# 9-ben lettek hozzáadva. A 6. figyelmeztető hullám diagnosztikái a C# 10-ben lettek hozzáadva. A 7. figyelmeztető hullám diagnosztikái a C# 11-ben lettek hozzáadva. A 8. figyelmeztető hullám diagnosztikái a C# 12-ben lettek hozzáadva. A 9. figyelmeztető hullám diagnosztikái a C# 13-ban lettek hozzáadva. A "10. figyelmeztető hullám" diagnosztikái a C# 14-ben kerültek hozzáadásra.

A .NET 7 SDK-tól kezdve (C# 11) a buildelési rendszer a következő szabályokkal állítja be a figyelmeztető hullámokat:

  • Az AnalysisLevel nyomon követi az aktuális TFM-et, ha nincs megadva
  • Az AnalysisLevel a legújabb értékre van állítva, ha az aktuális TFM a "legújabb" TFM (egy olyan tulajdonság meghatározása szerint, amelyet meg kell ütköznünk)
  • A WarningLevelnek nyomon kell követnie az aktuális TFM-et, ha nincs megadva
  • A WarningLevel nem bírálja felül a felhasználó által megadott értéket
  • A WarningLevel értéke 4, ha a projekt .NET-keretrendszer-projekt

A .NET 7-nél korábbi SDK-k esetében az AnalysisLevel mindig felülírja a WarningLevelet.

CS9265 – A mező soha nem lesz újra hozzárendelve, és mindig az alapértelmezett értékével fog rendelkezni.

Figyelmeztető hullám 10

A soha referenciaként meg nem adott ref mező a ref struct-ben mindig az alapértelmezett értéket, azaz egy null referenciát kap. A következő kód állítja elő a CS9265-öt:

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

A figyelmeztetés kezeléséhez rendelje hozzá újra a mezőt egy mező inicializálójában vagy az összes konstruktorkód elérési útján. Másik lehetőségként távolítsa el a ref módosítót a meződeklarációból, ha a mezőnek nem kell hivatkozásnak lennie.

CS9123 – A "&" operátor nem használható paramétereken vagy helyi változókon az aszinkron metódusokban

Figyelmeztető hullám 8

Az & operátor nem használható paramétereken vagy helyi változókon az aszinkron metódusokban. A következő kód állítja elő a CS9123-at:

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

CS8981 – A típusnév csak kisbetűs ascii karaktereket tartalmaz. Ezek a nevek a nyelv számára fenntartottak lehetnek.

Figyelmeztető hullám 7

A C#-hoz hozzáadott új kulcsszavak mind kisbetűs ASCII-karakterek lesznek. Ez a figyelmeztetés biztosítja, hogy egyik típus sem ütközik a jövőbeli kulcsszavakkal. A következő kód állítja elő a CS8981-et:

public class lowercasename
{
}

Ezt a figyelmeztetést úgy kezelheti, ha átnevezi a típust, hogy legalább egy nem kisbetűs ASCII-karaktert( például nagybetűt, számjegyet vagy aláhúzásjelet) tartalmazzon.

CS8826 – A részleges metódusdeklarációk aláírási eltérésekkel rendelkeznek.

6. figyelmeztetési hullám

Ez a figyelmeztetés kijavít néhány inkonzisztenciát a részleges metódus-aláírások közötti jelentési különbségekben. A fordító mindig hibát jelentett, amikor a részleges metódus-aláírások különböző CLR-aláírásokat hoztak létre. A fordító most a CS8826 hibát jelzi, ha az aláírások szintaktikailag eltérőek a C#-ban. Vegye figyelembe a következő részleges osztályt:

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

Az alábbi részleges osztály implementációja számos példát hoz létre a CS8626-ra:

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

Feljegyzés

Ha egy metódus megvalósítása nem null értékű hivatkozástípust használ, amikor a másik deklaráció null értékű hivatkozástípusokat fogad el, a CS8611 a CS8826 helyett jön létre.

A figyelmeztetések bármelyik ilyen példányának kijavításához győződjön meg arról, hogy a két aláírás egyezik.

CS7023 – Az "is" vagy "as" operátor második operandusa nem lehet statikus típus

5. figyelmeztetési hullám

A is kifejezések és as a kifejezések mindig statikus típushoz térnek vissza false , mert nem hozhatók létre statikus típusú példányok. A következő kód állítja elő a CS7023-at:

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

A fordító azért jelenti ezt a figyelmeztetést, mert a típusteszt soha nem lehet sikeres. A figyelmeztetés kijavításához távolítsa el a tesztet, és távolítsa el a végrehajtott kódot, ha a teszt sikeres volt. Az előző példában a else záradék mindig végrehajtásra kerül. A metódus törzsét a következő egyetlen sorra cserélheti:

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

CS8073 – A kifejezés eredménye mindig "érték", mivel a "type" típusú érték soha nem egyenlő a "type" típusú "null" értékkel

5. figyelmeztetési hullám

Az == és != operátorok mindig false (vagy true) eredményeznek, amikor egy struct típus példányát hasonlítják össze null-tel. Az alábbi kód bemutatja ezt a figyelmeztetést. Tegyük fel, hogy a S egy struct, amely meghatározza a operator == és a 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...
}

A hiba kijavításához távolítsa el az objektum nullesetén végrehajtandó null ellenőrzést és kódot.

CS8848 – A "from" operátor nem használható itt az elsőbbség miatt. Zárójelek használatával egyértelműsítsen.

5. figyelmeztetési hullám

Az alábbi példák ezt a figyelmeztetést mutatják be. Az operátorok precedenciája miatt a kifejezés helytelenül kötődik.

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];

A hiba kijavításához zárójeleket helyezzen el a lekérdezési kifejezés körül:

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

A tagokat teljes mértékben ki kell osztani. Nem hozzárendelt változó használata (CS8880, CS8881, CS8882, CS8883, CS8884, CS8885, CS8886, CS8887)

5. figyelmeztetési hullám

Számos figyelmeztetés javítja az importált szerelvényekben deklarált típusok határozott hozzárendelési elemzését struct . Ezek az új figyelmeztetések akkor jönnek létre, ha egy importált szerelvény egy szerkezetében egy hivatkozástípus elérhetetlen mezője (általában egy private mező) szerepel, ahogyan az alábbi példában látható:

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

Az alábbi példák a továbbfejlesztett határozott hozzárendelés-elemzésből származó figyelmeztetéseket mutatják be:

  • CS8880: Az automatikusan megvalósított "Tulajdonság" tulajdonságot teljes mértékben ki kell osztani, mielőtt a rendszer visszaadja a vezérlést a hívónak. Fontolja meg a "verzió" nyelvi verzióra való frissítését, hogy automatikusan alapértelmezett legyen a tulajdonság.
  • CS8881: A 'field' mezőt teljes mértékben ki kell osztani, mielőtt a vezérlés visszakerül a hívóhoz. Fontolja meg a "verzió" nyelvi verzióra való frissítését, hogy automatikusan alapértelmezett legyen a mező.
  • CS8882: A out paramétert hozzá kell rendelni, mielőtt a vezérlő elhagyja az aktuális metódust.
  • CS8883: Valószínűleg nem hozzárendelt, automatikusan implementált "Tulajdonság" tulajdonság használata.
  • CS8884: Az esetlegesen nem hozzárendelt 'Field' mező használata
  • CS8885: Az "ez" objektum nem használható az összes mező hozzárendelése előtt. Fontolja meg a nyelvi verzió 'verzióra' frissítését a nem hozzárendelt mezők automatikus alapértelmezéséhez.
  • CS8886: A "parameterName" nem hozzárendelt paraméter használata.
  • CS8887: A "variableName" nem hozzárendelt helyi változó használata
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;
    }
}

Ezen figyelmeztetések bármelyikét kijavíthatja, ha inicializálja vagy hozzárendeli az importált szerkezetet az alapértelmezett értékhez:

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 – A metódus nem használható belépési pontként, mert egy szinkron belépési pont "metódus" található.

5. figyelmeztetési hullám

Ez a figyelmeztetés akkor jön létre az összes aszinkron belépési pont jelöltjén, ha több érvényes belépési ponttal rendelkezik, beleértve egy vagy több szinkron belépési pontot is.

Az alábbi példa a CS8892-t hozza létre:

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

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

Feljegyzés

A fordító mindig a szinkron belépési pontot használja. Több szinkron belépési pont esetén fordítóhiba jelenik meg.

A figyelmeztetés kijavításához távolítsa el vagy nevezze át az aszinkron belépési pontot.

CS8897 – Statikus típusok nem használhatók paraméterekként

5. figyelmeztetési hullám

Az interfész tagjai nem deklarálhatnak olyan paramétereket, amelyek típusa statikus osztály. Az alábbi kód a CS8897-et és a CS8898-at is bemutatja:

public static class Utilities
{
    // elided
}

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

    // CS8898
    public Utilities GetUtility();
}

A figyelmeztetés kijavításához módosítsa a paraméter típusát, vagy távolítsa el a metódust.

CS8898 – A statikus típusok nem használhatók visszatérési típusokként

5. figyelmeztetési hullám

A felület tagjai nem deklarálhatnak statikus osztályt tartalmazó visszatérési típust. Az alábbi kód a CS8897-et és a CS8898-at is bemutatja:

public static class Utilities
{
    // elided
}

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

    // CS8898
    public Utilities GetUtility();
}

A figyelmeztetés kijavításához módosítsa a visszatérési típust, vagy távolítsa el a metódust.