Uttrykker hensikt
- 5 minutter
I den forrige enheten lærte du hvordan C#-kompilatoren kan utføre statisk analyse for å beskytte mot NullReferenceException. Du lærte også hvordan du aktiverer en kontekst som kan nullstilles. I denne enheten vil du lære mer om eksplisitt å uttrykke din hensikt i en nullbar kontekst.
Deklarering av variabler
Med en nullstillbar kontekst aktivert, har du mer synlighet i hvordan kompilatoren ser koden din. Du kan handle på advarslene som genereres fra en nullaktivert kontekst, og ved å gjøre dette definerer du eksplisitt intensjonene dine. La oss for eksempel fortsette å undersøke FooBar-koden og granske deklarasjonen og tildelingen:
// Define as nullable
FooBar? fooBar = null;
Legg merke til ? lagt til i FooBar. Dette forteller kompilatoren at du eksplisitt har tenkt at fooBar skal kunne nullstilles. Hvis du ikke har tenkt at fooBar skal kunne nullstilles, men du fremdeles vil unngå advarselen, bør du vurdere følgende:
// Define as non-nullable, but tell compiler to ignore warning
// Same as FooBar fooBar = default!;
FooBar fooBar = null!;
Dette eksemplet legger til operatoren null-tilgivende operator (!) i null, som instruerer kompilatoren om at du eksplisitt initialiserer denne variabelen som null. Kompilatoren vil ikke utstede advarsler om at denne referansen er null.
En god fremgangsmåte er å tilordne variabler som ikke kan nullstilles,null verdier når de deklareres, hvis mulig:
// Define as non-nullable, assign using 'new' keyword
FooBar fooBar = new(Id: 1, Name: "Foo");
Operatører
Som beskrevet i forrige enhet definerer C# flere operatorer for å uttrykke din hensikt rundt nullbare referansetyper.
Null-tilgivende (!) operator
Du ble introdusert for operatoren null tilgivende (!) i forrige del. Den ber kompilatoren om å ignorere CS8600-advarselen. Dette er en måte å fortelle kompilatoren at du vet hva du gjør, men det kommer med påminnelsen om at du bør faktisk vet hva du gjør!
Når du initialiserer typer som ikke kan nullstilles mens en nullbar kontekst er aktivert, må du kanskje eksplisitt be kompilatoren om tilgivelse. Vurder for eksempel følgende kode:
#nullable enable
using System.Collections.Generic;
var fooList = new List<FooBar>
{
new(Id: 1, Name: "Foo"),
new(Id: 2, Name: "Bar")
};
FooBar fooBar = fooList.Find(f => f.Name == "Bar");
// The FooBar type definition for example.
record FooBar(int Id, string Name);
I det foregående eksemplet genererer FooBar fooBar = fooList.Find(f => f.Name == "Bar"); en CS8600-advarsel, fordi Find kan returnere null. Denne mulige null vil bli tilordnet til fooBar, som ikke kan nullstilles i denne konteksten. Men i dette contrived eksemplet vet vi at Find aldri vil returnere null som skrevet. Du kan uttrykke denne hensikten med kompilatoren med operatoren null-tilgivende:
FooBar fooBar = fooList.Find(f => f.Name == "Bar")!;
Legg merke til ! på slutten av fooList.Find(f => f.Name == "Bar"). Dette forteller kompilatoren at du vet at objektet som returneres av Find metoden, kan være null, og det er greit.
Du kan også bruke null-tilgivende operatoren på en innebygd objektlinje før et metodekall eller en egenskapsevaluering. Vurder et annet contrived eksempel:
List<FooBar>? fooList = FooListFactory.GetFooList();
// Declare variable and assign it as null.
FooBar fooBar = fooList.Find(f => f.Name == "Bar")!; // generates warning
static class FooListFactory
{
public static List<FooBar>? GetFooList() =>
new List<FooBar>
{
new(Id: 1, Name: "Foo"),
new(Id: 2, Name: "Bar")
};
}
// The FooBar type definition for example.
record FooBar(int Id, string Name);
I det foregående eksemplet:
-
GetFooLister en statisk metode som returnerer en nullverditype,List<FooBar>?. -
fooListtilordnes verdien som returneres avGetFooList. - Kompilatoren genererer en advarsel på
fooList.Find(f => f.Name == "Bar");fordi verdien som er tilordnetfooList, kan værenull. - Forutsatt at
fooListikke ernull, kanFindreturnerenull, men vi vet at det ikke vil gjøre det, så operatoren for null-tilgivende brukes.
Du kan bruke null-tilgivende operatoren på fooList for å deaktivere advarselen:
FooBar fooBar = fooList!.Find(f => f.Name == "Bar")!;
Notat
Du bør bruke null-tilgivende operatoren judiciously. Hvis du bare bruker den til å avvise en advarsel, betyr det at du ber kompilatoren om ikke å hjelpe deg med å oppdage mulige null-uhell. Bruk det sparsomt, og bare når du er sikker.
Hvis du vil ha mer informasjon, kan du se ! (null-tilgivende) operator (C# referanse).
Null-koalescerende (??) operator
Når du arbeider med typer som kan nullstilles, må du kanskje vurdere om de for øyeblikket er null og utføre bestemte handlinger. Når for eksempel en nullverditype er tilordnet null eller de ikke er deinitialiserte, må du kanskje tilordne dem en verdi som ikke er null. Det er her null-coalescing operator (??) er nyttig.
Vurder følgende eksempel:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
salesTax ??= DefaultStateSalesTax.Value;
// Safely use salesTax object.
}
I den forrige C#-koden:
- Parameteren
salesTaxdefineres som en nullbarIStateSalesTax. - Innenfor metodeteksten tilordnes
salesTaxbetinget ved hjelp av operatoren null-coalescing.- Dette sikrer at hvis
salesTaxble sendt inn somnull, vil den ha en verdi.
- Dette sikrer at hvis
Tips
Dette tilsvarer funksjonelt følgende C#-kode:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
if (salesTax is null)
{
salesTax = DefaultStateSalesTax.Value;
}
// Safely use salesTax object.
}
Her er et eksempel på et annet vanlig C#-idiom der null-coalescing-operatoren kan være nyttig:
public sealed class Wrapper<T> where T : new()
{
private T _source;
// If given a source, wrap it. Otherwise, wrap a new source:
public Wrapper(T source = null) => _source = source ?? new T();
}
Den foregående C#-koden:
- Definerer en generell wrapper-klasse, der den generiske typeparameteren er begrenset til
new(). - Konstruktøren godtar en
T sourceparameter som standardnull. - Den innpakkede
_sourceinitialiseres betinget til ennew T().
Hvis du vil ha mer informasjon, kan du se ?? og?? = operatorer (C# referanse).
Null-betinget operator (?.)
Når du arbeider med typer som kan nullstilles, må du kanskje utføre handlinger betinget basert på tilstanden til et null objekt. For eksempel: i den forrige enheten ble FooBar posten brukt til å demonstrere NullReferenceException ved å utsette null. Dette ble forårsaket da ToString ble kalt. Vurder det samme eksemplet, men bruk nå den null-betingede operatoren:
using System;
// Declare variable and assign it as null.
FooBar fooBar = null;
// Conditionally dereference variable.
var str = fooBar?.ToString();
Console.Write(str);
// The FooBar type definition.
record FooBar(int Id, string Name);
Den foregående C#-koden:
- Betinget deferences
fooBar, tilordne resultatet avToStringtilstrvariabelen.- Variabelen
strer av typenstring?(nullbar streng).
- Variabelen
- Den skriver verdien av
strtil standardutdata, noe som ikke er noe. - Anrop
Console.Write(null)er gyldig, så det er ingen advarsler. - Du ville få en advarsel hvis du skulle ringe
Console.Write(str.Length)fordi du potensielt ville dereferencing null.
Tips
Dette tilsvarer funksjonelt følgende C#-kode:
using System;
// Declare variable and assign it as null.
FooBar fooBar = null;
// Conditionally dereference variable.
string str = (fooBar is not null) ? fooBar.ToString() : default;
Console.Write(str);
// The FooBar type definition.
record FooBar(int Id, string Name);
Du kan kombinere operatoren for å uttrykke din hensikt ytterligere. Du kan for eksempel kjede ?. og ?? operatorer:
FooBar fooBar = null;
var str = fooBar?.ToString() ?? "unknown";
Console.Write(str); // output: unknown
Hvis du vil ha mer informasjon, kan du se ?. og? [] (null-betinget) operatorer.
Sammendrag
I denne enheten lærte du om å uttrykke nullabilitetsintensjonen i kode. I neste enhet skal du bruke det du har lært på et eksisterende prosjekt.