Typy odkazů s možnou hodnotou null (Referenční dokumentace jazyka C#)

Poznámka

Tento článek popisuje typy odkazů s možnou hodnotou null. Můžete také deklarovat typy hodnot s možnou hodnotou null.

Typy odkazů s možnou hodnotou null jsou k dispozici počínaje jazykem C# 8,0, v kódu, který má výslovný přístup k kontextu s možnou hodnotou null. Odkazové typy s možnou hodnotou null, upozornění statické analýzy null a operátor null-striktní jsou volitelné funkce jazyka. Všechny jsou ve výchozím nastavení vypnuté. Kontext s možnou hodnotou null je řízen na úrovni projektu pomocí nastavení sestavení nebo v kódu pomocí direktiv pragma.

V kontextu s možnou hodnotou null:

  • Proměnná typu odkazu T musí být inicializována s jinou hodnotou než null a nikdy jí nemůže být přiřazena hodnota, která může být null .
  • Proměnná typu odkazu T? může být inicializována null nebo přiřazena null , ale je nutné ji před odkazem zrušit na kontrolu null .
  • Proměnná m typu T? je považována za nenulové, pokud použijete operátor null-striktní, jako v m! .

Rozdíly mezi typem odkazu, který neumožňuje hodnotu null T , a odkazem na typ s možnou hodnotou null T? jsou vynásobeny interpretací předchozích pravidel kompilátoru. Proměnná typu T a proměnná typu T? jsou reprezentovány stejným typem .NET. Následující příklad deklaruje řetězec nepovolující hodnotu null a řetězec s možnou hodnotou null a poté používá operátor null-striktní k přiřazení hodnoty k řetězci, který nemůže mít hodnotu null:

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

Proměnné notNull a nullable jsou zastoupeny String typem. Vzhledem k tomu, že typy neumožňující hodnotu null a povolující hodnotu null jsou uloženy jako stejný typ, existuje několik míst, kde použití typu odkazu s možnou hodnotou null není povoleno. Obecně platí, že typ odkazu s možnou hodnotou null se nedá použít jako základní (Base) třídu nebo implementované rozhraní. Typ odkazu s možnou hodnotou null se nedá použít ve výrazu pro vytvoření objektu nebo testování typu. Typ odkazu s možnou hodnotou null nemůže být typem výrazu přístupu člena. Následující příklady znázorňují tyto konstrukce:

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

Odkazy s možnou hodnotou null a statická analýza

Příklady v předchozí části ilustrují povahu odkazů typu s možnou hodnotou null. Typy odkazů s možnou hodnotou null nejsou nové typy tříd, ale místo toho poznámky na existující typy odkazů. Kompilátor používá tyto poznámky, které vám pomohou najít potenciální chyby nulového odkazu ve vašem kódu. Neexistuje rozdíl za běhu mezi odkazovým typem, který nepovoluje hodnotu null, a typem odkazu s možnou hodnotou null. Kompilátor nepřidá žádnou kontrolu za běhu pro typy odkazů, které neumožňují hodnotu null. Výhody jsou v analýze při kompilaci. Kompilátor generuje upozornění, která vám pomůžou najít a opravit potenciální chyby null ve vašem kódu. Deklarujete svůj záměr a kompilátor vás upozorní, když váš kód porušuje tento záměr.

V kontextu s povolenou hodnotou null provede kompilátor statickou analýzu proměnných libovolného typu odkazu, který může mít hodnotu null a nemůže mít hodnotu null. Kompilátor sleduje hodnotu null pro každou proměnnou reference jako buď NOT-NULL , nebo pravděpodobně-null. Výchozí stav odkazu, který neumožňuje hodnotu null, není null. Výchozí stav odkazu s možnou hodnotou null je pravděpodobně null.

Odkazové typy, které neumožňují hodnotu null, by měly být vždy bezpečné, aby bylo možné odkázat, protože jejich stav null není -null. Chcete-li toto pravidlo vyhodnotit, kompilátor vydá upozornění, pokud není typ odkazu, který není null, inicializován na hodnotu jinou než null. Místní proměnné musí být přiřazeny tam, kde jsou deklarovány. Každé poli musí být přiřazena hodnota, která není null , v inicializátoru pole nebo v každém konstruktoru. Kompilátor vystavuje upozornění, když je odkaz, který nepovoluje hodnotu null, přiřazen k odkazu, jehož stav je pravděpodobně null. Obecně platí, že odkaz, který neumožňuje hodnotu null, není null a při odkázání na tyto proměnné nejsou vydávána žádná upozornění.

Poznámka

Pokud přiřadíte výraz, který je pravděpodobně null , na odkazový typ, který nepovoluje hodnotu null, kompilátor vygeneruje upozornění. Kompilátor potom vygeneruje upozornění pro tuto proměnnou, dokud není přiřazena ke výrazu, který není null .

Typy odkazů s možnou hodnotou null mohou být inicializovány nebo přiřazeny null . Statická analýza proto musí určit, že proměnná není null , než bude předána zpětná reference. Pokud je odkaz s možnou hodnotou null roven hodnotě null, přiřazení k referenční proměnné, která nepovoluje hodnotu null, vygeneruje upozornění kompilátoru. Následující třída ukazuje příklady těchto upozornění:

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

Následující fragment kódu ukazuje, kde kompilátor generuje upozornění při použití této třídy:

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

Předchozí příklady ukazují, jak statická analýza kompilátoru Určuje stav hodnoty null referenčních proměnných. Kompilátor aplikuje jazyková pravidla pro kontroly null a přiřazení pro informování o analýze. Kompilátor nemůže vytvořit předpoklady o sémantikě metod nebo vlastností. Pokud voláte metody, které provádějí kontroly hodnoty null, kompilátor nemůže znát tyto metody, které ovlivňují stav null proměnné. Existují atributy, které můžete přidat do rozhraní API, abyste informovali kompilátor o sémantikě argumentů a vrácených hodnot. Tyto atributy byly aplikovány na mnoho běžných rozhraní API v knihovnách .NET Core. Například IsNullOrEmpty byl aktualizován a kompilátor správně interpretuje tuto metodu jako kontrolu s hodnotou null. Další informace o atributech, které se vztahují na statickou analýzu stavu null , najdete v článku o atributech s možnou hodnotounull.

Nastavení kontextu s možnou hodnotou null

Existují dva způsoby, jak řídit kontext s možnou hodnotou null. Na úrovni projektu můžete přidat <Nullable>enable</Nullable> nastavení projektu. V jednom zdrojovém souboru C# můžete přidat #nullable enable direktivu pragma a povolit tak kontext s možnou hodnotou null. Přečtěte si článek o Nastavení strategie s možnou hodnotou null. Před verzí .NET 6 používají nové projekty výchozí, <Nullable>disable</Nullable> . Počínaje rozhraním .NET 6 obsahují nové projekty <Nullable>enable</Nullable> prvek v souboru projektu.

specifikace jazyka C#

Další informace najdete v následujících návrzích pro specifikaci jazyka C#:

Viz také