Verweis Typen, die NULL-Werte zulassen in C #Nullable reference types in C#

Ziel dieses Features ist Folgendes:The goal of this feature is to:

  • Ermöglicht es Entwicklern, auszudrücken, ob eine Variable, ein Parameter oder ein Ergebnis eines Verweis Typs NULL sein soll oder nicht.Allow developers to express whether a variable, parameter or result of a reference type is intended to be null or not.
  • Geben Sie Warnungen an, wenn derartige Variablen, Parameter und Ergebnisse nicht gemäß dieser Absicht verwendet werden.Provide warnings when such variables, parameters and results are not used according to that intent.

Ausdruck der AbsichtExpression of intent

Die Sprache enthält bereits die T? Syntax für Werttypen.The language already contains the T? syntax for value types. Es ist einfach, diese Syntax auf Verweis Typen auszuweiten.It is straightforward to extend this syntax to reference types.

Es wird davon ausgegangen, dass es sich bei der Absicht eines unzierten Verweis Typs um einen T nicht-NULL-Wert handelt.It is assumed that the intent of an unadorned reference type T is for it to be non-null.

Überprüfen von verweisen, die NULL zulassenChecking of nullable references

Eine Fluss Analyse verfolgt Verweis Variablen, die NULL-Werte zulassen.A flow analysis tracks nullable reference variables. Wenn die Analyse nicht NULL ist (z. b. nach einer Überprüfung oder einer Zuweisung), wird Ihr Wert als nicht-NULL-Verweis betrachtet.Where the analysis deems that they would not be null (e.g. after a check or an assignment), their value will be considered a non-null reference.

Ein Verweis, der NULL-Werte zulässt, kann auch explizit mit dem postfix- x! Operator (dem "Damnit"-Operator) als ungleich NULL behandelt werden, wenn die Fluss Analyse keine nicht-NULL-Situation festlegen kann, die der Entwickler kennt.A nullable reference can also explicitly be treated as non-null with the postfix x! operator (the "damnit" operator), for when flow analysis cannot establish a non-null situation that the developer knows is there.

Andernfalls wird eine Warnung ausgegeben, wenn ein Verweis, der NULL-Werte zulässt, dereferenziert wird oder in einen nicht-NULL-Typ konvertiert wird.Otherwise, a warning is given if a nullable reference is dereferenced, or is converted to a non-null type.

Beim Umstellen von S[] in T?[] und von in wird eine Warnung S?[] ausgegeben T[] .A warning is given when converting from S[] to T?[] and from S?[] to T[].

Beim Umrechnen von in wird eine Warnung ausgegeben C<S> C<T?> , es sei denn, der Typparameter ist kovariant ( out ), und bei der Umstellung von C<S?> auf ist C<T> der Typparameter kontra Variant ( in ).A warning is given when converting from C<S> to C<T?> except when the type parameter is covariant (out), and when converting from C<S?> to C<T> except when the type parameter is contravariant (in).

C<T?>Wenn der Typparameter Einschränkungen ungleich NULL aufweist, wird eine Warnung ausgegeben.A warning is given on C<T?> if the type parameter has non-null constraints.

Überprüfen von nicht-NULL-verweisenChecking of non-null references

Eine Warnung wird ausgegeben, wenn ein NULL-wahrsten einer Variablen ungleich NULL zugewiesen oder als nicht-NULL-Parameter übergeben wird.A warning is given if a null literal is assigned to a non-null variable or passed as a non-null parameter.

Eine Warnung wird auch ausgegeben, wenn ein Konstruktor nicht NULL-Verweis Felder explizit initialisiert.A warning is also given if a constructor does not explicitly initialize non-null reference fields.

Wir können nicht ausreichend nachverfolgen, ob alle Elemente eines Arrays von verweisen, die nicht NULL sind, initialisiert werden.We cannot adequately track that all elements of an array of non-null references are initialized. Wir könnten jedoch eine Warnung ausgeben, wenn kein Element eines neu erstellten Arrays zugewiesen wird, bevor das Array gelesen oder weitergereicht wird.However, we could issue a warning if no element of a newly created array is assigned to before the array is read from or passed on. Dies kann den häufigen Fall verarbeiten, ohne zu stark zu sein.That might handle the common case without being too noisy.

Wir müssen entscheiden, ob default(T) eine Warnung generiert oder einfach als Typ behandelt wird T? .We need to decide whether default(T) generates a warning, or is simply treated as being of the type T?.

MetadatendarstellungMetadata representation

Zusatzelemente der NULL-Zulässigkeit sollten in Metadaten als Attribute dargestellt werden.Nullability adornments should be represented in metadata as attributes. Dies bedeutet, dass downlevelcompiler diese ignorieren.This means that downlevel compilers will ignore them.

Wir müssen entscheiden, ob nur NULL-Werte zulässig sind, oder es gibt Aufschluss darüber, ob ein nicht-NULL-Element in der Assembly "on" war.We need to decide if only nullable annotations are included, or there's also some indication of whether non-null was "on" in the assembly.

GenericsGenerics

Wenn ein Typparameter T Einschränkungen aufweist, die keine NULL-Werte zulassen, wird er innerhalb seines Gültigkeits Bereichs als nicht auf NULL festlegbar behandelt.If a type parameter T has non-nullable constraints, it is treated as non-nullable within its scope.

Wenn ein Typparameter nicht eingeschränkt ist oder nur NULL-Werte zulässt, ist die Situation etwas komplexer: Dies bedeutet, dass das entsprechende Typargument entweder NULL-Werte zulässt oder keine NULL-Werte zulässt.If a type parameter is unconstrained or has only nullable constraints, the situation is a little more complex: this means that the corresponding type argument could be either nullable or non-nullable. Die in dieser Situation sichere Aufgabe besteht darin, den Typparameter sowohl als Werte zulässt als auch als nicht-NULL-Werte zu behandeln, und es werden Warnungen ausgegeben, wenn eine Verletzung auftritt.The safe thing to do in that situation is to treat the type parameter as both nullable and non-nullable, giving warnings when either is violated.

Es lohnt sich zu erwägen, ob explizite Verweis Einschränkungen auf NULL-Werte zulässig sind.It is worth considering whether explicit nullable reference constraints should be allowed. Beachten Sie jedoch, dass es nicht möglich ist, Verweis Typen, die NULL-Werte zulassen, implizit in bestimmten Fällen eingeschränkt zu werden (geerbte Einschränkungen).Note, however, that we cannot avoid having nullable reference types implicitly be constraints in certain cases (inherited constraints).

Die class Einschränkung ist nicht NULL.The class constraint is non-null. Wir können berücksichtigen, ob class? eine gültige Einschränkung, die NULL-Werte zulässt, eine gültige Einschränkung ist, die NULL-Werte zulässt.We can consider whether class? should be a valid nullable constraint denoting "nullable reference type".

TyprückschlussType inference

Wenn beim Typrückschluss ein Mitwirkender Typ ein Verweistyp ist, der NULL-Werte zulässt, sollte der resultierende Typ NULL-Werte zulassen.In type inference, if a contributing type is a nullable reference type, the resulting type should be nullable. Das heißt, dass NULL-Werte weitergegeben werden.In other words, nullness is propagated.

Wir sollten berücksichtigen, ob das null Literale als teilnehmende Ausdruck NULL sein sollte.We should consider whether the null literal as a participating expression should contribute nullness. Dies ist heute nicht der Fall: für Werttypen führt dies zu einem Fehler, während für Verweis Typen der NULL-Wert erfolgreich in den Plain-Typ konvertiert wird.It doesn't today: for value types it leads to an error, whereas for reference types the null successfully converts to the plain type.

string? n = "world";
var x = b ? "Hello" : n; // string?
var y = b ? "Hello" : null; // string? or error
var z = b ? 7 : null; // Error today, could be int?

Leitfaden zu NULL-SchutzNull guard guidance

Als Funktion können die Verweis Typen, die NULL-Werte zulassen, ihre Absicht ausdrücken und Warnungen über die Fluss Analyse bereitstellen, wenn diese Absicht widerspricht.As a feature, nullable reference types allow developers to express their intent, and provide warnings through flow analysis if that intent is contradicted. Es gibt eine häufige Frage, ob NULL-Wächter erforderlich sind oder nicht.There is a common question as to whether or not null guards are necessary.

Beispiel für NULL GuardExample of null guard

public void DoWork(Worker worker)
{
    // Guard against worker being null
    if (worker is null)
    {
        throw new ArgumentNullException(nameof(worker));
    }

    // Otherwise use worker argument
}

Im vorherigen Beispiel DoWork akzeptiert die Funktion eine Worker und schützt Sie, die möglicherweise ist null .In the previous example, the DoWork function accepts a Worker and guards against it potentially being null. Wenn das- worker Argument ist null , DoWork wird die Funktion verwendet throw .If the worker argument is null, the DoWork function will throw. Bei Verweis Typen, die NULL-Werte zulassen, hat der Code im vorherigen Beispiel die Absicht, dass der- Worker Parameter nicht ist null .With nullable reference types, the code in the previous example makes the intent that the Worker parameter would not be null. Wenn es sich bei der DoWork Funktion um eine öffentliche API handelt, wie z. b. ein nuget-Paket oder eine freigegebene Bibliothek, sollten Sie als Leitfaden NULL-Wächter vorhanden lassen.If the DoWork function was a public API, such as a NuGet package or a shared library - as guidance you should leave null guards in place. Als öffentliche API ist die einzige Garantie, dass ein Aufrufer nicht weitergereicht, null darauf zu schützen.As a public API, the only guarantee that a caller isn't passing null is to guard against it.

Express IntentExpress intent

Eine überzeugendere Verwendung des vorherigen Beispiels besteht darin, auszudrücken, dass der Worker Parameter möglicherweise ist null , sodass der NULL-Schutz besser geeignet ist.A more compelling use of the previous example is to express that the Worker parameter could be null, thus making the null guard more appropriate. Wenn Sie den nullguard im folgenden Beispiel entfernen, warnt der Compiler, dass Sie möglicherweise null dereferenzieren.If you remove the null guard in the following example, the compiler warns that you may be dereferencing null. Beide NULL-Wächter sind immer noch gültig.Regardless, both null guards are still valid.

public void DoWork(Worker? worker)
{
    // Guard against worker being null
    if (worker is null)
    {
        throw new ArgumentNullException(nameof(worker));
    }

    // Otherwise use worker argument
}

Bei nicht öffentlichen APIs, wie z. b. Quellcode, der von einem Entwickler-oder Entwicklerteam vollständig gesteuert wird, können die Verweis Typen, die NULL-Werte zulassen, das sichere Entfernen von NULL-Schutzkräften ermöglichen, wenn die Entwickler garantieren können, dass Sie nicht erforderlich sindFor non-public APIs, such as source code entirely in control by a developer or dev team - the nullable reference types could allow for the safe removal of null guards where the developers can guarantee it is not necessary. Die-Funktion kann bei Warnungen helfen, aber es kann nicht garantiert werden, dass die Ausführung eines Lauf Zeit Codes zu einer führen könnte NullReferenceException .The feature can help with warnings, but it cannot guarantee that at runtime code execution could result in a NullReferenceException.

Aktuelle ÄnderungenBreaking changes

Warnungen ungleich NULL sind eine offensichtliche Breaking Change für vorhandenen Code und sollten mit einem Opt-in-Mechanismus einhergehen.Non-null warnings are an obvious breaking change on existing code, and should be accompanied with an opt-in mechanism.

Weniger offensichtlich sind Warnungen von Typen, die NULL-Werte zulassen (wie oben beschrieben), eine Breaking Change auf vorhandenem Code in bestimmten Szenarien, in denen die NULL-Zulässigkeit implizit ist:Less obviously, warnings from nullable types (as described above) are a breaking change on existing code in certain scenarios where the nullability is implicit:

  • Nicht eingeschränkte Typparameter werden als implizit NULL-Werte behandelt, sodass die Zuweisung object oder der Zugriff auf z. b. ToString Warnungen liefert.Unconstrained type parameters will be treated as implicitly nullable, so assigning them to object or accessing e.g. ToString will yield warnings.
  • Wenn Typrückschluss NULL-Werte von null Ausdrücken ableitet, gibt vorhandener Code in manchen Fällen NULL-Werte als nicht auf NULL festleg Bare Typen zurück, was zu neuen Warnungen führen kann.if type inference infers nullness from null expressions, then existing code will sometimes yield nullable rather than non-nullable types, which can lead to new warnings.

Daher müssen auf NULL festleg Bare Warnungen ebenfalls optional sein.So nullable warnings also need to be optional

Zum Schluss ist das Hinzufügen von Anmerkungen zu einer vorhandenen API eine Breaking Change für Benutzer, die sich für Warnungen entschieden haben, wenn Sie die Bibliothek aktualisieren.Finally, adding annotations to an existing API will be a breaking change to users who have opted in to warnings, when they upgrade the library. Dies hat auch die Möglichkeit, sich zu entscheiden. "Ich möchte die Fehlerbehebungen, aber ich bin nicht bereit, mit ihren neuen Anmerkungen umzugehen"This, too, merits the ability to opt in or out. "I want the bug fixes, but I am not ready to deal with their new annotations"

Zusammenfassend müssen Sie in der Lage sein, Folgendes zu abonnieren:In summary, you need to be able to opt in/out of:

  • NULL-Werte zulassenNullable warnings
  • Nicht-NULL-WarnungenNon-null warnings
  • Warnungen von Anmerkungen in anderen DateienWarnings from annotations in other files

Die Granularität der Zustimmung deutet auf ein Analyse ähnliches Modell hin, bei dem sich Teil Striche mit Pragmas anmelden können, und Schweregrade können vom Benutzer ausgewählt werden.The granularity of the opt-in suggests an analyzer-like model, where swaths of code can opt in and out with pragmas and severity levels can be chosen by the user. Außerdem kann es sein, dass pro Bibliothek-Optionen ("die Anmerkungen von JSON.net ignorieren, bis ich bereit für den Umgang mit dem Fallout sind") möglicherweise im Code als Attribute ausgedrückt werden kann.Additionally, per-library options ("ignore the annotations from JSON.NET until I'm ready to deal with the fall out") may be expressible in code as attributes.

Der Entwurf der Opt-in-/Übergangs--Funktion ist entscheidend für den Erfolg und die Nützlichkeit dieses Features.The design of the opt-in/transition experience is crucial to the success and usefulness of this feature. Wir müssen Folgendes sicherstellen:We need to make sure that:

  • Benutzer können die Überprüfung der NULL-Zulässigkeit nach und nach nach Bedarf übernehmenUsers can adopt nullability checking gradually as they want to
  • Bibliotheks Autoren können NULL-Zulässigkeit-Anmerkungen hinzufügenLibrary authors can add nullability annotations without fear of breaking customers
  • Obwohl dies nicht der Fall ist, ist "Konfigurations Alptraum" nicht sinnvoll.Despite these, there is not a sense of "configuration nightmare"

AnpassungenTweaks

Wir könnten die ? Anmerkungen nicht für lokale Variablen verwenden, sondern nur beobachten, ob Sie in Übereinstimmung mit den Ihnen zugewiesenen Elementen verwendet werden.We could consider not using the ? annotations on locals, but just observing whether they are used in accordance with what gets assigned to them. Ich bevorzuge dies nicht. Ich denke, wir sollten den Benutzern die Absicht überlassen, ihre Absicht auszudrücken.I don't favor this; I think we should uniformly let people express their intent.

Wir könnten einen Kurzwert T! x für Parameter in Erwägung gezogen, der automatisch eine NULL-Lauf Zeit Überprüfung generiert.We could consider a shorthand T! x on parameters, that auto-generates a runtime null check.

Bestimmte Muster bei generischen Typen, wie z. FirstOrDefault b. oder TryGet , weisen ein etwas seltsames Verhalten mit nicht auf NULL festleg baren Typargumenten auf, da Sie in bestimmten Situationen explizit Standardwerte ergeben.Certain patterns on generic types, such as FirstOrDefault or TryGet, have slightly weird behavior with non-nullable type arguments, because they explicitly yield default values in certain situations. Wir könnten versuchen, das Typsystem zu unterstützen, um diese bessere Anpassung zu ermöglichen.We could try to nuance the type system to accommodate these better. Beispielsweise können wir ? mit nicht eingeschränkten Typparametern zulassen, obwohl das Typargument bereits NULL-Werte zulassen kann.For instance, we could allow ? on unconstrained type parameters, even though the type argument could already be nullable. Ich bin mir sicher, dass es Wert ist, und es führt zu einer Bedeutung, die sich auf die Interaktion mit auf NULL festleg baren Werttypen bezieht.I doubt that it is worth it, and it leads to weirdness related to interaction with nullable value types.

Auf NULL festlegbare WerttypenNullable value types

Wir könnten auch einige der obigen Semantik für Werttypen, die NULL-Werte zulassen, in Erwägung gezogen.We could consider adopting some of the above semantics for nullable value types as well.

Wir haben bereits den Typrückschluss erwähnt, bei dem wir aus ableiten konnten int? (7, null) , anstatt nur einen Fehler zu geben.We already mentioned type inference, where we could infer int? from (7, null), instead of just giving an error.

Eine weitere Möglichkeit besteht darin, die Fluss Analyse auf Werte zulässt-Werttypen anzuwenden.Another opportunity is to apply the flow analysis to nullable value types. Wenn Sie als ungleich Null angesehen werden, können wir die Verwendung von als nicht auf NULL festleg baren Typ auf bestimmte Weise zulassen (z. b. Element Zugriff).When they are deemed non-null, we could actually allow using as the non-nullable type in certain ways (e.g. member access). Wir müssen nur darauf achten, dass die Dinge, die Sie bereits für einen Werte zulässt-Werttyp ausführen können, für die Back-Kompatibilitäts-Gründe bevorzugt werden.We just have to be careful that the things that you can already do on a nullable value type will be preferred, for back compat reasons.