Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Tip
Neu bei nullablen Verweistypen? Lesen Sie zunächst Nullable-Referenztypen, um Anmerkungen und die NULL-Zustandsanalyse zu verstehen. In diesem Artikel wird davon ausgegangen, dass Warnungen in einem Projekt angezeigt werden, in dem das Feature aktiviert ist.
Suchen Sie nach einem bestimmten Compilerfehlercode? Der Referenzartikel NULL-Warnungen beheben führt alle CS86xx-Warnungen mit der passenden Technik auf.
Wenn Sie nullfähige Verweistypen aktivieren, gibt der Compiler Warnungen überall aus, wo das Verhalten des Codes nicht mit seinen Anmerkungen übereinstimmt. Die meisten Warnungen fallen in einen kleinen Satz von Mustern. Sobald Sie das Muster erkannt haben, ist der Fix in der Regel eine von fünf Techniken:
- Fügen Sie eine NULL-Prüfung hinzu.
- Fügen Sie eine
?oder!Annotation hinzu oder entfernen Sie sie. - Fügen Sie ein Attribut hinzu, das den Null-Vertrag beschreibt.
- Initialisieren Sie Variablen richtig.
- Überprüfen Sie die Projekteinstellung.
In diesem Artikel werden die einzelnen Techniken mit einem repräsentativen Beispiel erläutert. Das Ziel ist nicht, Warnungen zu unterdrücken. Sie müssen die Nullbehandlungsabsicht des Codes explizit festlegen, damit der Compiler dieselben Schlussfolgerungen erreicht, die Sie tun.
Nullstatus: was der Compiler nachverfolgt
Bevor Sie sich die Techniken ansehen, hilft es zu wissen, wie der Compiler potenzielle Null-Zustandsverletzungen verfolgt. Während sie Ihren Code liest, verfolgt der Compiler den NULL-Zustand jedes Ausdrucks: seine Analyse darüber, ob sich der Ausdruck an diesem Punkt im Code befinden null könnte. Der NULL-Zustand ist einer von zwei Werten:
-
not-null - der Compiler kann beweisen, dass der Ausdruck nicht
nullhier ist. Sie können es ohne Überprüfung sicher verwenden. -
vielleicht-null - der Compiler kann nicht ausschließen
null. Wenn Sie den Ausdruck verwenden, ohne ihn zu überprüfen, wird eine Warnung erzeugt.
Der NULL-Zustand einer Variablen ändert sich, wenn der Compiler ihrem Code folgt. Eine Methode, die möglicherweise null zurückgibt, liefert ein Maybe-Null-Ergebnis. Eine if (x is not null) Prüfung schränkt x innerhalb des if-Blocks auf not-null ein. Die angezeigten Warnungen sind Warnungen des Compilers, die Ihnen mitteilen, dass er festgestellt hat, dass sich ein Ausdruck im Zustand maybe-null befindet und Sie ihn nun so verwenden wollen, als wäre er not-null. Jedes Verfahren im rest dieses Artikels ist eine andere Möglichkeit, dem Compiler die Informationen zu geben, die er benötigt, um sicherzustellen, dass ein Ausdruck nicht null ist, bevor Sie ihn verwenden.
Hinzufügen einer NULL-Prüfung
Die häufigste Warnung ist die Mögliche Ableitung von NULL. Der Compiler hat den Nullzustand einer Variablen als maybe-null erkannt und festgestellt, dass die Variable ohne Nullprüfung verwendet wurde:
public static int LengthOfMessageUnsafe(string? message)
{
// Warning CS8602: dereference of a possibly null reference.
return message.Length;
}
Die Lösung ist in der Regel eine Guard-Klausel. Eine Guard-Klausel ist eine Überprüfung am anfang einer Methode oder eines Blocks, die zurückgegeben oder ausgelöst wird, wenn eine Eingabe ungültig ist. Nur der sichere Pfad wird fortgesetzt. Sobald die Überprüfung ausgeführt wird, aktualisiert der Compiler den NULL-Zustand der Variablen auf "not-null " im sicheren Pfad:
public static int DereferenceFixed(string? message)
{
if (message is null)
{
return 0;
}
// No warning: the compiler knows message is not-null on this path.
return message.Length;
}
Musterabgleich (Ausdrücke wie is null oder is { } die die Form eines Werts testen) ??und ??= NULL-Prüfungen enthalten:
public static int NullOperatorsFix(string? message)
{
// ?. evaluates to null if message is null; ?? supplies the fallback value.
int length = message?.Length ?? 0;
// Pattern matching narrows the type on the matching branch.
if (message is { Length: > 0 })
{
length = message.Length;
}
return length;
}
Das Eigenschaftenmuster { Length: > 0 } passt nur, wenn message nicht NULL ist und seine Eigenschaft Length größer als null ist, sodass der Compiler message innerhalb des Blocks if als nicht NULL behandelt. Ein einfacherer is not null Test liefert dieselbe Einschränkung auf den Null-Zustand, ohne Eigenschaften zu prüfen.
Eine ausführliche Tour durch die Betreiber finden Sie unter Null-Operatoren.
Anpassen von Anmerkungen
Der Compiler warnt Sie auch, wenn Ihr Code einer Nicht-NULL-Variablen einen Ausdruck, der möglicherweise NULL ist, zuweist. Diese Warnung bedeutet eine von zwei Dingen:
- Die Variable sollte Nullwerte zulassen. Fügen Sie in diesem Fall dem Typ ein
?hinzu. - Der Ausdruck erzeugt niemals einen NULL-Wert. Kommentieren Sie die API, die sie erstellt hat.
public static void AssignmentWarning()
{
// Warning CS8600: converting null literal or possible null value to non-nullable type.
string name = Lookup("nobody");
Console.WriteLine(name);
}
Wenn Lookup legitim null zurückgegeben wird, ändern Sie die Aufrufwebsite so, dass der fehlende Wert akzeptiert wird:
public static void AssignmentFixed()
{
string? name = Lookup("somebody");
if (name is not null)
{
Console.WriteLine(name);
}
}
Wenn Lookup nie null zurückgegeben wird, ändern Sie die Signatur, um einen nicht nullfähigen Verweistyp zurückzugeben. Szenarien, in denen der NULL-Zustand des zurückgegebenen Werts von der Eingabe abhängig ist, finden Sie im folgenden Abschnitt zu Nullanalyseattributen.
Verwenden Sie den Operator ! null-forgiving nur, wenn Sie garantieren können, dass ein Wert nicht null ist, aber diese Garantie nicht im Typsystem ausdrücken kann. Jeder ! Ist ein Ort, an dem der Compiler Sie nicht mehr schützen kann, bevorzugen Sie daher das Hinzufügen einer Überprüfung oder Anmerkungen zur Quell-API.
Hinzufügen eines Nullanalyse-Attributs
Manchmal liegt die richtige Lösung nicht an der Aufrufstelle. Die Signatur einer Methode erfasst nicht genau genug die Beziehung zwischen ihren Eingaben und Ausgaben, und der Compiler gibt Warnungen innerhalb von ansonsten sicherem Code aus:
public static bool IsPresent(string? text) =>
!string.IsNullOrEmpty(text);
public static void CallerWithoutAttribute(string? text)
{
if (IsPresent(text))
{
// Warning CS8602: dereference of a possibly null reference.
// The signature doesn't tell the compiler text is not-null here.
Console.WriteLine(text.Length);
}
}
Der Rumpf von IsPresent beweist, dass das Argument nicht null ist, wenn die Methode true zurückgibt, aber die Signatur drückt das nicht aus. Fügen Sie ein nullables Analyse-Attribut hinzu, um den Vertragsteil der API zu erstellen:
public static bool AttributedIsPresent([NotNullWhen(true)] string? text) =>
!string.IsNullOrEmpty(text);
public static void CallerWithAttribute(string? text)
{
if (AttributedIsPresent(text))
{
// No warning: the attribute tells the compiler text is not-null.
Console.WriteLine(text.Length);
}
}
Zu den allgemeinen Attributen gehören:
- NotNullWhenAttribute — das Argument ist nicht null , wenn die Methode den angegebenen booleschen Wert zurückgibt.
- NotNullIfNotNullAttribute — der Rückgabewert ist nicht null , wenn das benannte Argument nicht null ist.
- MemberNotNullAttribute — die aufgelisteten Elemente sind nach der Rückkehr der Methode nicht Null.
- DoesNotReturnAttribute — die Methode gibt niemals normal zurück (z. B. wird sie immer ausgelöst).
Die vollständige Liste ist in nullablen statischen Analyseattributen enthalten.
Initialisieren von Membern, die nicht NULL sein dürfen
Eine Konstruktorwarnung bedeutet, dass ein Nicht-NULL-Feld, eine Eigenschaft oder eine automatisch implementierte Eigenschaft (eine Eigenschaft, die das vom Compiler generierte Unterstützungsfeld verwendet, z. B. public string Name { get; set; }) beim Verlassen des Konstruktors keinen Wert ungleich NULL zugewiesen bekommen hat:
public class PersonUninitialized
{
// Warning CS8618: Non-nullable property 'Name' is uninitialized.
public string Name { get; set; }
}
Sie haben mehrere Möglichkeiten, dies zu beheben. Wählen Sie die Option aus, die Ihrer Designabsicht am besten entspricht.
Den Wert als Konstruktorargument angeben. Verwenden Sie einen primären Konstruktor (Parameter, die für den Typ selbst deklariert sind, der im gesamten Textkörper verfügbar ist) oder einen regulären Konstruktor, der die Eigenschaft initialisiert:
public class PersonInjected(string name)
{
public string Name { get; } = name;
}
Legen Sie die Eigenschaft requiredfest. Der Aufrufer muss es über einen Objektinitialisierer initialisieren (mit der { Property = value }-Syntax, die auf new folgt):
public class PersonRequired
{
public required string Name { get; init; }
}
Mit einem Standardwert initialisieren. Wenn der Typ einen sinnvollen leeren Wert hat, initialisieren Sie ihn bei der Deklaration:
public class PersonInitialized
{
public string Name { get; set; } = "John Doe";
}
Tip
Wählen Sie diese Technik nur dann, wenn der Typ einen wirklich guten Standardwert hat: einen Wert, der eine gültige, vollfunktionsfähige Instanz darstellt, die vom aufrufenden Code verwendet werden kann. Beispiele sind leere Sammlungen. Erfinden Sie keinen Wächterwert (einen Platzhalterwert wie String.Empty, "N/A", "unknown" oder -1, den Sie als „kein Wert“ behandeln) als Ersatz für null: Dadurch wird die Warnung zwar unterdrückt, aber jeder Aufrufer muss den Wächterwert kennen und darauf prüfen, und das Typsystem kann dabei nicht helfen. Wenn kein sinnvoller Standardwert vorhanden ist, deklarieren Sie die Eigenschaft stattdessen als nullable.
Legen Sie die Eigenschaft nullwerte fest. Wenn der Wert tatsächlich fehlen kann, ändern Sie den Typ in nullable:
public class PersonOptional
{
public string? Name { get; set; }
}
Wenn eine Hilfsmethode das Member initialisiert, versehen Sie die Hilfsmethode mit MemberNotNullAttribute, damit der Compiler Aufrufe an diese Methode entsprechend anrechnen kann.
Überprüfen der Projekteinstellung
Neue C#-Projekte aktivieren standardmäßig nullfähige Verweistypen, sodass der meiste Code, den Sie schreiben oder lesen, bereits das Feature aktiviert hat. Im Allgemeinen müssen Sie nichts konfigurieren. Wenn Sie wissen möchten, ob es für ein Projekt aktiviert ist oder Sie die Einstellung ändern müssen, suchen Sie in der .csproj nach dem <Nullable>-Element:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Die allgemeinen unterstützten Werte sind enable (standard für neue Projekte) und disable. Wenn das Element fehlt, verwendet das Projekt die standardeinstellung für das SDK und das Zielframework.
Wenn Sie Nullable nur für einen Teil einer Datei mit #nullable-Direktiven aktivieren müssen oder beim Migrieren einer vorhandenen Codebasis die partiellen Modi warnings und annotations verwenden, lesen Sie Migrationsstrategien für Nullable.
Nächste Schritte
Wenn eine Warnung in keines dieser Muster passt, werden im Referenzartikel "Beheben von Nullable-Warnungen" die geeigneten Techniken für jede vom Compiler ausgegebene CS86xx-Warnung aufgeführt.
Informationen zum Planen einer Migration, die nullable Verweistypen in einer vorhandenen Codebasis schrittweise ermöglicht, finden Sie unter Nullable Migrationsstrategien.