Om nullabilitet
Hvis du er .NET-udvikler, er det sandsynligt, at du er stødt på System.NullReferenceException. Dette sker på kørselstidspunktet, når der henvises til en null. dvs. når en variabel evalueres på kørselstidspunktet, men variablen refererer til null. Denne undtagelse er langt den mest almindelige undtagelse i .NET-økosystemet. Skaberen af null, Sir Tony Hoare, henviser til null som "milliard-dollar fejl."
I følgende eksempel tildeles variablen FooBar til null og straks dereferencer, hvilket medfører problemet:
// Declare variable and assign it as null.
FooBar fooBar = null;
// Dereference variable by calling ToString.
// This will throw a NullReferenceException.
_ = fooBar.ToString();
// The FooBar type definition.
record FooBar(int Id, string Name);
Problemet bliver meget sværere at få øje på som udvikler, når dine apps vokser i størrelse og kompleksitet. Det er en opgave at spotte potentielle fejl som dette, og C#-compileren er her for at hjælpe.
Definition af null-sikkerhed
Udtrykket null-sikkerhed definerer et sæt funktioner, der er specifikke for typer, der kan være null,, der hjælper med at reducere antallet af mulige NullReferenceException forekomster.
I betragtning af det forrige FooBar eksempel kan du undgå NullReferenceException ved at kontrollere, om variablen fooBar blev null før dereferencing af den:
// Declare variable and assign it as null.
FooBar fooBar = null;
// Check for null
if (fooBar is not null)
{
_ = fooBar.ToString();
}
// The FooBar type definition for example.
record FooBar(int Id, string Name);
For at hjælpe med at identificere scenarier som denne kan compileren udlede hensigten med din kode og gennemtvinge den ønskede funktionsmåde. Dette er dog kun, når en kontekst, der kan være null, er aktiveret. Før vi diskuterer kontekst, der kan være null, skal vi beskrive de mulige typer, der kan være null.
Typer, der kan være null
Før C# 2.0 var det kun referencetyper, der kunne være null. Værdityper som int eller DateTimekunne ikke være null. Hvis disse typer initialiseres uden en værdi, falder de tilbage til deres default værdi. Hvis der er tale om en int, er dette 0. For en DateTimeer det DateTime.MinValue.
Referencetyper, der er instantieret uden startværdier, fungerer anderledes. Værdien default for alle referencetyper er null.
Overvej følgende C#-kodestykke:
string first; // first is null
string second = string.Empty // second is not null, instead it's an empty string ""
int third; // third is 0 because int is a value type
DateTime date; // date is DateTime.MinValue
I det foregående eksempel:
-
firsternull, fordi referencetypenstringblev erklæret, men der ikke blev foretaget nogen tildeling. -
secondtildelesstring.Empty, når den erklæres. Objektet har aldrig haft ennulltildeling. -
thirder0, selvom den ikke er tildelt. Det er enstruct(værditype) og har endefaultværdi på0. -
dateer ikke initialiseret, men densdefaultværdi er System.DateTime.MinValue.
Fra og med C# 2.0 kan du definere værdityper, der kan være null, ved hjælp af Nullable<T> (eller T? til stenografi). Dette gør det muligt for værdityper at være null. Overvej følgende C#-kodestykke:
int? first; // first is implicitly null (uninitialized)
int? second = null; // second is explicitly null
int? third = default; // third is null as the default value for Nullable<Int32> is null
int? fourth = new(); // fourth is 0, since new calls the nullable constructor
I det foregående eksempel:
-
firsternull, fordi værditypen, der kan være null, ikke er initialiseret. -
secondtildelesnull, når den erklæres. -
thirdernull, dadefault-værdien forNullable<int>ernull. -
fourther0, da udtrykketnew()kalder denNullable<int>konstruktør, ogint0som standard.
C# 8.0 introducerede referencetyper, der kan være null,, hvor du kan angive, at en referencetype, der være null, eller altid ikke-null. Du tænker måske: "Jeg troede, at alle referencetyper kan være null!" Du tager ikke fejl, og det gør de. Denne funktion giver dig mulighed for at udtrykke din hensigt, som compileren derefter forsøger at gennemtvinge. Den samme T? syntaks udtrykker, at en referencetype er beregnet til at være null.
Overvej følgende C#-kodestykke:
#nullable enable
string first = string.Empty;
string second;
string? third;
I det foregående eksempel udleder compileren din hensigt på følgende måde:
-
firster aldrignull, da det helt sikkert er tildelt. -
secondbør aldrig værenull, selvom det oprindeligt ernull. Evaluering afsecondfør tildeling af en værdi resulterer i en kompileringsadvarsel, da den ikke initialiseres. -
thirdkan værenull. Det kan f.eks. pege på enSystem.String, men det kan pege pånull. Begge disse variationer er acceptable. Compileren hjælper dig med at advare dig, hvis du refererthirduden først at kontrollere, at den ikke er null.
Vigtig
Hvis du vil bruge funktionen referencetyper, der kan være null, som vist ovenfor, skal den være inden for en kontekst, der kan være null . Dette er beskrevet i næste afsnit.
Kontekst, der kan være null
Kontekster, der kan være null, aktiverer detaljeret kontrol af, hvordan compileren fortolker referencetypevariabler. Der er fire mulige kontekster, der kan være null:
-
disable: Compileren fungerer på samme måde som C# 7.3 og tidligere. -
enable: Compileren aktiverer alle null-referenceanalyser og alle sprogfunktioner. -
warnings: Compileren udfører alle null-analyser og udsender advarsler, når kode kan afvigenull. -
annotations: Compileren udfører ikke null-analyser eller udsender advarsler, når kode kan afvigenull, men du kan stadig anmærke din kode ved hjælp af referencetyper, der kan være null,?og operatorer, der er null tilgivende (!).
Dette modul er begrænset til enten disable eller enable kontekster, der kan være null. Du kan få flere oplysninger ved at referere Referencetyper, der kan være null: Kontekster, der kan være null,.
Aktivér referencetyper, der kan være null
I C#-projektfilen (.csproj) skal du føje en underordnet <Nullable> node til <Project>-elementet (eller føje til et eksisterende <PropertyGroup>). Dette vil anvende enable kontekst, der kan være null, på hele projektet.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- Omitted for brevity -->
</Project>
Du kan også bruge kontekst, der kan være null, til en C#-fil ved hjælp af et kompileringsdirektiv.
#nullable enable
Det foregående C#-kompileringsdirektiv svarer funktionelt til projektkonfigurationen, men det er begrænset til den fil, hvor det er placeret. Du kan få flere oplysninger under Referencetyper, der kan være null: Null-kontekster (docs)
Vigtig
Konteksten, der kan være null, er som standard aktiveret i filen .csproj i alle C#-projektskabeloner, der starter med .NET 6.0 og nyere.
Når konteksten, der kan være null, er aktiveret, får du nye advarsler. Overvej det forrige FooBar eksempel, som indeholder to advarsler, når de analyseres i en kontekst, der kan være null:
Den
FooBar fooBar = null;linje indeholder en advarsel pånull-tildelingen: C# Advarsel CS8600: Konverterer en null-konstantværdi eller en mulig null-værdi til en type, der ikke kan være null,.Linjen
_ = fooBar.ToString();indeholder også en advarsel. Denne gang er compileren bekymret for, atfooBarkan være null: C# Advarsel CS8602: Reference for en reference, der muligvis er null,.
Vigtig
Der er ingen garanteret null-sikkerhed, selvom du reagerer på og fjerner alle advarsler. Der er nogle begrænsede scenarier, der vil bestå compilerens analyse, men alligevel resultere i en kørsel NullReferenceException.
Resumé
I dette undermodul har du lært at aktivere en kontekst, der kan være null, i C# for at beskytte mod NullReferenceException. I det næste undermodul får du mere at vide om eksplicit at udtrykke din hensigt i en kontekst, der kan være null.