Nullable-Verweistypen (C#-Referenz)

Hinweis

Dieser Artikel behandelt Nullable-Verweistypen. Sie können auch Nullable-Werttypen deklarieren.

Nullable-Verweistypen sind im Code verfügbar, der für NULL-kompatiblen Kontext aktiviert wurde. Nullable-Verweistypen, Warnungen bei statischer Analyse des NULL-Status und der NULL-tolerante Operator sind optionale Sprachfeatures. Alle sind standardmäßig deaktiviert. Ein NULL-kompatibler Kontext wird auf Projektebene mithilfe von Buildeinstellungen oder im Code mithilfe von Pragmas festgelegt.

Wichtig

Alle Projektvorlagen ab .NET 6 (C# 10) aktivieren den Nullable-Kontext für das Projekt. Projekte, die mit früheren Vorlagen erstellt wurden, enthalten dieses Element nicht, sodass diese Features deaktiviert sind, es sei denn, Sie aktivieren sie in der Projektdatei oder Sie verwenden Pragmas.

In einem NULL-kompatiblen Kontext gilt Folgendes:

  • Eine Variable mit dem Verweistyp T muss ohne NULL-Werte initialisiert werden, und ihr darf kein Wert zugewiesen werden, der null sein kann.
  • Eine Variable mit dem Verweistyp T? kann mit null initialisiert oder null zugewiesen werden, muss jedoch vor der Dereferenzierung auf null geprüft werden.
  • Eine m-Variable vom Typ T? wird als ungleich NULL betrachtet, wenn Sie den NULL-toleranten Operator wie in m! anwenden.

Die Unterschiede zwischen dem Non-Nullable-Verweistyp T und dem Nullable-Verweistyp T? werden so erzwungen, wie der Compiler die vorhergehenden Regeln interpretiert. Eine Variable vom Typ T und eine Variable vom Typ T? werden durch denselben .NET-Typ dargestellt. Im folgenden Beispiel werden eine Non-Nullable-Zeichenfolge und eine Nullable-Zeichenfolge deklariert. Anschließend wird der NULL-tolerante Operator verwendet, um einer Non-Nullable-Zeichenfolge einen Wert zuzuweisen:

string notNull = "Hello";
string? nullable = default;
notNull = nullable!; // null forgiveness

Die Variablen notNull und nullable werden beide durch den String-Typ dargestellt. Da Non-Nullable- und Nullable-Typen als derselbe Typ gespeichert werden, gibt es mehrere Speicherorte, an denen Nullable-Verweistypen nicht verwendet werden dürfen. Ein Nullable-Verweistyp kann generell nicht als Basisklasse oder implementierte Schnittstelle verwendet werden. Ein Nullable-Verweistyp kann nicht in Ausdrücken für Objekterstellung oder Typtests verwendet werden. Ein Nullable-Verweistyp kann nicht der Typ eines Memberzugriffsausdrucks sein. In den folgenden Beispielen werden diese Konstrukte veranschaulicht:

public MyClass : System.Object? // not allowed
{
}

var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
    if (thing is string? nullableString) // not allowed
        Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
    Console.WriteLine("error");
}

Nullable-Verweise und statische Analyse

Die Beispiele im vorherigen Abschnitt veranschaulichen den Charakter von Nullable-Verweistypen. Nullable-Verweistypen sind keine neuen Klassentypen, sondern eher Annotationen zu vorhandenen Verweistypen. Der Compiler verwendet diese Annotationen, um potenzielle NULL-Verweisfehler in Ihrem Code zu finden. Für Non-Nullable-Verweistypen und Nullable-Verweistypen werden keine unterschiedlichen Runtimes verwendet. Der Compiler fügt keine Runtime hinzu, die auf Non-Nullable-Verweistypen prüft. Die Vorteile liegen in der Analyse zur Kompilierzeit. Der Compiler generiert Warnungen, die Ihnen helfen, potenzielle NULL-Fehler in Ihrem Code zu finden und zu beheben. Sie deklarieren Ihre Absicht, und der Compiler warnt Sie, wenn Ihr Code gegen diese Absicht verstößt.

In NULL-kompatiblem Kontext führt der Compiler eine statische Analyse für Variablen für Nullable- und Non-Nullable-Verweistypen durch. Der Compiler erfasst den null-state jeder Verweisvariablen entweder als not-null (nicht NULL) oder als maybe-null (vielleicht NULL). Der Standardstatus eines nicht Nullwerte zulassenden Verweises ist not null (nicht NULL). Der Standardstatus eines Nullwerte zulassenden Verweises ist maybe null (vielleicht NULL).

Keine Nullwerte zulassende Verweistypen müssen immer sicher dereferenziert werden, da ihr NULL-Statusnot-null (nicht NULL) ist. Der Compiler erzwingt diese Regel, indem Warnungen ausgegeben werden, wenn ein Non-Nullable-Verweistyp nicht in einen Wert ungleich NULL initialisiert wird. Lokale Variablen müssen dort zugewiesen werden, wo sie auch deklariert werden. Jedem Feld muss in einem Feldinitialisierer bzw. in jedem Konstruktor ein Wert zugewiesen werden, der not-null (nicht Null) ist. Der Compiler gibt Warnungen aus, wenn ein keine Nullwerte zulassender Verweis einem Verweis zugeordnet wird, dessen Status maybe null (vielleicht NULL) ist. Da ein keine Nullwerte zulassender Verweis jedoch den Status not null (nicht NULL) hat, werden keine Warnungen ausgegeben, wenn diese Variablen dereferenziert werden.

Hinweis

Wenn Sie einen maybe-null-Ausdruck einem Non-Nullable-Verweistyp zuweisen, erzeugt der Compiler eine Warnung. Der Compiler erzeugt dann Warnungen für diese Variable, bis sie einem Ausdruck zugewiesen wird, der not-null (nicht null) ist.

Nullable-Verweistypen können initialisiert oder null zugewiesen werden. Daher muss bei der statischen Analyse bestätigt werden, dass eine Variable not null (nicht NULL) ist, bevor sie dereferenziert wird. Wenn ein Nullwerte zulassender Verweis als maybe-nullable (vielleicht NULL) bestimmt wird, erzeugt die Zuweisung an eine keine Nullwerte zulassende Verweisvariable eine Compilerwarnung. In der folgenden Klasse werden Beispiele für diese Warnungen veranschaulicht:

public class ProductDescription
{
    private string shortDescription;
    private string? detailedDescription;

    public ProductDescription() // Warning! shortDescription not initialized.
    {
    }

    public ProductDescription(string productDescription) =>
        this.shortDescription = productDescription;

    public void SetDescriptions(string productDescription, string? details=null)
    {
        shortDescription = productDescription;
        detailedDescription = details;
    }

    public string GetDescription()
    {
        if (detailedDescription.Length == 0) // Warning! dereference possible null
        {
            return shortDescription;
        }
        else
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
    }

    public string FullDescription()
    {
        if (detailedDescription == null)
        {
            return shortDescription;
        }
        else if (detailedDescription.Length > 0) // OK, detailedDescription can't be null.
        {
            return $"{shortDescription}\n{detailedDescription}";
        }
        return shortDescription;
    }
}

Im folgenden Codeausschnitt sehen Sie, an welcher Stelle der Compiler bei Verwendung dieser Klasse Warnungen ausgibt:

string shortDescription = default; // Warning! non-nullable set to null;
var product = new ProductDescription(shortDescription); // Warning! static analysis knows shortDescription maybe null.

string description = "widget";
var item = new ProductDescription(description);

item.SetDescriptions(description, "These widgets will do everything.");

In den vorangehenden Beispielen wird die statische Analyse des Compilers veranschaulicht, mit der der NULL-Status von Verweisvariablen bestimmt wird. Der Compiler wendet Sprachregeln auf NULL-Prüfungen und -Zuweisungen an, um die Analyse mit Informationen zu versorgen. Der Compiler kann keine Annahmen zur Semantik von Methoden oder Eigenschaften treffen. Wenn Sie Methoden aufzurufen, die NULL-Prüfungen durchführen, kann der Compiler nicht wissen, welche Methoden den NULL-Status einer Variablen beeinflussen. Es gibt einige Attribute, die Sie Ihren APIs hinzufügen können, um den Compiler über die Semantik von Argumenten und Rückgabewerten zu informieren. Diese Attribute wurden auf viele gängige APIs in den .NET Core-Bibliotheken angewendet. Beispielsweise wurde IsNullOrEmpty aktualisiert, und der Compiler interpretiert diese Methode ordnungsgemäß als NULL-Prüfung. Weitere Informationen zu den Attributen für die statische Analyse des null-state finden Sie im Artikel zu Nullwerte zulassenden Attributen.

Festlegen des NULL-kompatiblen Kontexts

Es gibt zwei Möglichkeiten, den NULL-kompatiblen Kontext festzulegen. Auf Projektebene können Sie die Projekteinstellung <Nullable>enable</Nullable> hinzufügen. In einer einzelnen C#-Quelldatei können Sie das #nullable enable-Pragma hinzufügen, um den NULL-kompatiblen Kontext zu aktivieren. Weitere Informationen finden Sie im Artikel zum Festlegen einer NULL-kompatiblen Strategie. Vor .NET 6 wurde für neue Projekte der Standardwert <Nullable>disable</Nullable> verwendet. Ab .NET 6 enthalten neue Projekte das <Nullable>enable</Nullable>-Element in allen Projektvorlagen.

C#-Sprachspezifikation

Weitere Informationen finden Sie in den folgenden Vorschlägen für die C#-Sprachspezifikation:

Weitere Informationen