Referenstyper som kan användas som null (C#-referens)

Kommentar

Den här artikeln beskriver nullbara referenstyper. Du kan också deklarera nullbara värdetyper.

Nullbara referenstyper är tillgängliga i kod som har valt en nullbar medveten kontext. Ogiltiga referenstyper, varningar om statisk analys av null och null-förlåtande operatorn är valfria språkfunktioner. Alla är inaktiverade som standard. En nullbar kontext styrs på projektnivå med hjälp av bygginställningar eller i kod med hjälp av pragmas.

Viktigt!

Alla projektmallar som börjar med .NET 6 (C# 10) aktiverar den nullbara kontexten för projektet. Projekt som skapats med tidigare mallar inkluderar inte det här elementet, och dessa funktioner är inaktiverade om du inte aktiverar dem i projektfilen eller använder pragmas.

I en null-medveten kontext:

  • En variabel av en referenstyp T måste initieras med icke-null och får aldrig tilldelas ett värde som kan vara null.
  • En variabel av en referenstyp T? kan initieras med null eller tilldelas null, men måste kontrolleras innan null referensen tas bort.
  • En variabel m av typen T? anses vara icke-null när du använder operatorn null-forgiving, som i m!.

Distinktionerna mellan en referenstyp T som inte är nullbar och en nullbar referenstyp T? framtvingas av kompilatorns tolkning av föregående regler. En variabel av typen T och en variabel av typen T? representeras av samma .NET-typ. I följande exempel deklareras en icke-nullbar sträng och en nullbar sträng och använder sedan operatorn null-forgiving för att tilldela ett värde till en icke-nullbar sträng:

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

Variablerna notNull och nullable representeras båda av String typen . Eftersom de icke-nullbara och nullbara typerna båda lagras som samma typ finns det flera platser där det inte är tillåtet att använda en nullbar referenstyp. I allmänhet kan en null-referenstyp inte användas som basklass eller implementerat gränssnitt. Det går inte att använda en nullbar referenstyp vid skapande av objekt eller typtestuttryck. En nullbar referenstyp kan inte vara typen av medlemsåtkomstuttryck. Följande exempel visar dessa konstruktioner:

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

Null-referenser och statisk analys

Exemplen i föregående avsnitt illustrerar typen av null-referenstyper. Nullbara referenstyper är inte nya klasstyper, utan snarare anteckningar om befintliga referenstyper. Kompilatorn använder dessa anteckningar för att hitta potentiella null-referensfel i koden. Det finns ingen körningsskillnad mellan en referenstyp som inte kan null och en referenstyp som kan ogiltigförklaras. Kompilatorn lägger inte till någon körningskontroll för referenstyper som inte går att nolla. Fördelarna finns i kompileringstidsanalysen. Kompilatorn genererar varningar som hjälper dig att hitta och åtgärda potentiella null-fel i koden. Du deklarerar din avsikt och kompilatorn varnar dig när koden bryter mot den avsikten.

I en null-aktiverad kontext utför kompilatorn statisk analys på variabler av alla referenstyper, både null- och icke-nullbara. Kompilatorn spårar null-tillståndet för varje referensvariabel som antingen inte null eller kanske null. Standardtillståndet för en icke-nullbar referens är inte null. Standardtillståndet för en nullbar referens är kanske null.

Referenstyper som inte är nullbara bör alltid vara säkra att avreferera eftersom deras null-tillstånd inte är null. För att framtvinga den regeln utfärdar kompilatorn varningar om en referenstyp som inte kan nulliseras inte initieras till ett värde som inte är null. Lokala variabler måste tilldelas där de deklareras. Varje fält måste tilldelas ett värde som inte är null , i en fältinitierare eller varje konstruktor. Kompilatorn utfärdar varningar när en referens som inte kan nulleras tilldelas en referens vars tillstånd kanske är null. I allmänhet är en icke-nullbar referens inte null och inga varningar utfärdas när dessa variabler derefereras.

Kommentar

Om du tilldelar ett kanske null-uttryck till en referenstyp som inte går att nolla genererar kompilatorn en varning. Kompilatorn genererar sedan varningar för variabeln tills den har tilldelats ett uttryck som inte är null .

Null-referenstyper kan initieras eller tilldelas till null. Statisk analys måste därför fastställa att en variabel inte är null innan den derefereras. Om en nullbar referens bedöms vara kanske null genererar tilldelning till en referensvariabel som inte kan nulleras en kompilatorvarning. Följande klass visar exempel på dessa varningar:

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

Följande kodfragment visar var kompilatorn genererar varningar när den här klassen används:

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

Föregående exempel visar hur kompilatorns statiska analys avgör null-tillståndet för referensvariabler. Kompilatorn tillämpar språkregler för null-kontroller och tilldelningar för att informera analysen. Kompilatorn kan inte göra antaganden om semantiken för metoder eller egenskaper. Om du anropar metoder som utför null-kontroller kan kompilatorn inte veta att dessa metoder påverkar en variabels null-tillstånd. Det finns attribut som du kan lägga till i dina API:er för att informera kompilatorn om semantiken för argument och returvärden. Dessa attribut har tillämpats på många vanliga API:er i .NET Core-biblioteken. Till exempel IsNullOrEmpty har uppdaterats och kompilatorn tolkar metoden korrekt som en null-kontroll. Mer information om de attribut som gäller för statisk analys med null-tillstånd finns i artikeln om null-attribut.

Ange den nullbara kontexten

Det finns två sätt att styra den nullbara kontexten. På projektnivå kan du lägga till projektinställningen <Nullable>enable</Nullable> . I en enda C#-källfil kan du lägga till #nullable enable pragma för att aktivera den nullbara kontexten. Se artikeln om hur du anger en nullbar strategi. Före .NET 6 använder nya projekt standardvärdet . <Nullable>disable</Nullable> Från och med .NET 6 innehåller nya projekt elementet <Nullable>enable</Nullable> i projektfilen.

Språkspecifikation för C#

Mer information finns i följande förslag för C#-språkspecifikationen:

Se även