Intentie uitdrukken
In de vorige les hebt u geleerd hoe de C#-compiler statische analyse kan uitvoeren om u te beschermen NullReferenceException
. U hebt ook geleerd hoe u een null-context inschakelt. In deze les leert u meer over het expliciet uitdrukken van uw intentie in een null-context.
Variabelen declareren
Als een null-context is ingeschakeld, hebt u meer inzicht in hoe de compiler uw code ziet. U kunt reageren op de waarschuwingen die zijn gegenereerd op basis van een context met null-functionaliteit. In dat opzicht definieert u expliciet uw intenties. Laten we bijvoorbeeld doorgaan met het onderzoeken van de FooBar
code en het onderzoeken van de declaratie en toewijzing:
// Define as nullable
FooBar? fooBar = null;
Noteer de ?
toegevoegde aan FooBar
. Hiermee wordt aan de compiler aangegeven dat u expliciet van plan bent fooBar
nullable te zijn. Als u niet van plan fooBar
bent nullable te zijn, maar u toch de waarschuwing wilt vermijden, kunt u het volgende overwegen:
// Define as non-nullable, but tell compiler to ignore warning
// Same as FooBar fooBar = default!;
FooBar fooBar = null!;
In dit voorbeeld wordt de operator null-forgiving (!
) toegevoegd aan null
, waarmee de compiler wordt geïnstrueerd dat u deze variabele expliciet initialiseert als null. De compiler geeft geen waarschuwingen over deze verwijzing die null is.
Een goede gewoonte is om uw niet-null-variabelen niet-waardennull
toe te wijzen wanneer ze indien mogelijk worden gedeclareerd:
// Define as non-nullable, assign using 'new' keyword
FooBar fooBar = new(Id: 1, Name: "Foo");
Operators
Zoals besproken in de vorige les, definieert C# verschillende operators om uw intentie uit te drukken rond null-referentietypen.
Null-forgiving-operator (!
)
U hebt kennisgemaakt met de operator null-forgiving (!
) in de vorige sectie. Hiermee wordt aan de compiler aangegeven dat de cs8600-waarschuwing moet worden genegeerd. Dit is een manier om de compiler te vertellen dat u weet wat u doet, maar het komt met het voorbehoud dat u eigenlijk moet weten wat u doet.
Wanneer u niet-nullable typen initialiseert terwijl een null-context is ingeschakeld, moet u de compiler mogelijk expliciet om vergeving vragen. Denk bijvoorbeeld aan de volgende code:
#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);
In het voorgaande voorbeeld FooBar fooBar = fooList.Find(f => f.Name == "Bar");
wordt een CS8600-waarschuwing gegenereerd, omdat Find
deze mogelijk wordt geretourneerd null
. Dit kan null
worden toegewezen aan fooBar
, wat in deze context niet nullable is. In dit gewende voorbeeld weten we echter dat dat Find
nooit zal terugkeren null
als geschreven. U kunt deze intentie naar de compiler uitdrukken met de operator null-forgiving:
FooBar fooBar = fooList.Find(f => f.Name == "Bar")!;
Noteer de !
aan het einde van fooList.Find(f => f.Name == "Bar")
. Dit vertelt de compiler dat u weet dat het object dat door de Find
methode wordt geretourneerd, mogelijk is null
en dat het geen probleem is.
U kunt de operator null-forgiving ook toepassen op een object inline vóór een methodeaanroep of evaluatie van eigenschappen. Kijk eens naar een ander voorbeeld:
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);
In het voorgaande voorbeeld:
GetFooList
is een statische methode die een null-type retourneert,List<FooBar>?
.fooList
wordt de waarde toegewezen die wordt geretourneerd doorGetFooList
.- De compiler genereert een waarschuwing omdat
fooList.Find(f => f.Name == "Bar");
de waarde die aan deze compiler is toegewezenfooList
, mogelijk isnull
. - Ervan uitgaande
fooList
dat dit nietnull
het resultaat is,Find
kan worden geretourneerdnull
, maar we weten dat dat niet het gaat, dus de operator null-forgiving wordt toegepast.
U kunt de operator null-forgiving toepassen om de waarschuwing uit te fooList
schakelen:
FooBar fooBar = fooList!.Find(f => f.Name == "Bar")!;
Notitie
U moet de operator null-forgiving zorgvuldig gebruiken. Als u deze gewoon gebruikt om een waarschuwing te sluiten, betekent dit dat u de compiler niet vertelt dat u mogelijke null-mishaps kunt detecteren. Gebruik het spaarzaam en alleen wanneer u zeker bent.
Voor meer informatie, naslag ! (null-forgiving)-operator (C#-verwijzing).
Operator Null-coalescing (??
)
Wanneer u met null-typen werkt, moet u mogelijk evalueren of deze momenteel null
zijn en bepaalde acties uitvoeren. Wanneer bijvoorbeeld een null-type is toegewezen null
of niet-geïnitialiseerd is, moet u deze mogelijk een niet-null-waarde toewijzen. Hier is de operator null-coalescing (??
) handig.
Kijk een naar het volgende voorbeeld:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
salesTax ??= DefaultStateSalesTax.Value;
// Safely use salesTax object.
}
In de voorgaande C#-code:
- De
salesTax
parameter wordt gedefinieerd als een null-waardeIStateSalesTax
. - Binnen de hoofdtekst van de methode wordt de
salesTax
voorwaardelijk toegewezen met behulp van de operator null-coalescing.- Dit zorgt ervoor dat als
salesTax
deze is doorgegeven,null
een waarde heeft.
- Dit zorgt ervoor dat als
Tip
Dit is functioneel gelijk aan de volgende C#-code:
public void CalculateSalesTax(IStateSalesTax? salesTax = null)
{
if (salesTax is null)
{
salesTax = DefaultStateSalesTax.Value;
}
// Safely use salesTax object.
}
Hier volgt een voorbeeld van een andere veelvoorkomende C#-idioom waarbij de operator null-coalescing nuttig kan zijn:
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();
}
De voorgaande C#-code:
- Definieert een algemene wrapper-klasse, waarbij de parameter voor het algemene type is beperkt tot
new()
. - De constructor accepteert een
T source
parameter die standaard is ingesteldnull
op . - De wrapped
_source
wordt voorwaardelijk geïnitialiseerd naar eennew T()
.
Bekijk voor meer informatie ?? en ?? = operatoren (C#-verwijzing).
Operator null-voorwaardelijk (?.
)
Wanneer u werkt met null-typen, moet u mogelijk voorwaardelijke acties uitvoeren op basis van de status van een null
object. Bijvoorbeeld: in de vorige eenheid werd de FooBar
record gebruikt om te demonstreren NullReferenceException
door deferencing null
. Dit werd veroorzaakt toen het ToString
werd aangeroepen. Bekijk hetzelfde voorbeeld, maar pas nu de null-voorwaardelijke operator toe:
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);
De voorgaande C#-code:
- Voorwaardelijk deducties
fooBar
, waarbij het resultaat vanToString
destr
variabele wordt toegewezen.- De
str
variabele is van het typestring?
(nullable string).
- De
- De waarde van
str
de standaarduitvoer wordt weggeschreven. Dit is niets. - Bellen
Console.Write(null)
is geldig, dus er zijn geen waarschuwingen. - U krijgt een waarschuwing als u zou bellen
Console.Write(str.Length)
, omdat u mogelijk null zou deductie ongedaan maken.
Tip
Dit is functioneel gelijk aan de volgende C#-code:
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);
U kunt operator combineren om uw intentie verder uit te drukken. U kunt de operatoren ??
bijvoorbeeld koppelen?.
:
FooBar fooBar = null;
var str = fooBar?.ToString() ?? "unknown";
Console.Write(str); // output: unknown
Raadpleeg de operators ?. en ?[] (null-conditional) voor meer informatie.
Samenvatting
In deze les hebt u geleerd over het uitdrukken van uw intentie voor null-baarheid in code. In de volgende les past u toe wat u hebt geleerd op een bestaand project.