Inzicht in null-baarheid
Als je een .NET-ontwikkelaar bent, heb je waarschijnlijk de System.NullReferenceException tegengekomen. Dit gebeurt tijdens de uitvoering wanneer een null wordt gedereferenceerd; dat wil zeggen, wanneer een variabele tijdens runtime wordt geëvalueerd, maar de variabele verwijst naar null. Deze uitzondering is verreweg de meest voorkomende uitzondering binnen het .NET-ecosysteem. De maker van null, Sir Tony Hoare, verwijst naar null de 'miljard dollar fout'.
In het volgende voorbeeld wordt de FooBar-variabele toegewezen aan null en onmiddellijk gedereferentieerd, waardoor het probleem optreedt.
// 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);
Het probleem wordt veel moeilijker te herkennen als ontwikkelaar wanneer uw apps groter en complexer worden. Het opsporen van mogelijke fouten zoals dit is een taak voor hulpprogramma's en de C#-compiler is er om u te helpen.
Null-veiligheid definiëren
De term null-veiligheid definieert een set functies die specifiek zijn voor null-typen die helpen het aantal mogelijke NullReferenceException exemplaren te verminderen.
In het vorige FooBar voorbeeld kunt u NullReferenceException vermijden door te controleren of de fooBar variabele null was voordat u deze derefereert.
// 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);
Om te helpen bij het identificeren van scenario's zoals deze, kan de compiler de intentie van uw code afleiden en het gewenste gedrag afdwingen. Dit is echter alleen wanneer een nullable context is ingeschakeld. Voordat u de null-context bespreekt, gaan we de mogelijke null-typen beschrijven.
Optionele typen
Vóór C# 2.0 waren alleen verwijzingstypen null-baar. Waardetypen zoals int of DateTime kunnen niet zijnnull. Als deze typen worden geïnitialiseerd zonder een waarde, vallen ze terug op hun default waarde. In het geval van een int, is dit 0. Voor een DateTime, het is DateTime.MinValue.
Verwijzingstypen die worden geïnstantieerd zonder initiële waarden werken anders. De default waarde voor alle referentietypen is null.
Bekijk het volgende C#-fragment:
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
In het voorgaande voorbeeld:
-
firstisnullomdat het referentietypestringis gedeclareerd, maar er geen toewijzing is gemaakt. -
secondwordtstring.Emptytoegewezen wanneer het wordt gedeclareerd. Het object had nooit eennullopdracht. -
thirdis0ondanks dat het niet is toegewezen. Het is eenstruct(waardetype) en heeft eendefaultwaarde van0. -
dateis niet geïnitialiseerd, maar dedefaultwaarde is System.DateTime.MinValue.
Vanaf C# 2.0 kunt u null-waardetypen definiëren met behulp van Nullable<T> (of T? voor afkorting). Hierdoor kunnen waardetypen null-baar zijn. Bekijk het volgende C#-fragment:
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
In het voorgaande voorbeeld:
-
firstisnullomdat het nulbare waardetype niet geïnitialiseerd is. -
secondwordtnulltoegewezen wanneer het wordt gedeclareerd. -
thirdisnullzoals dedefaultwaarde voorNullable<int>isnull. - Zoals de
fourth-expressie de0-constructor aanroept, isnew()Nullable<int>, en isintstandaard0.
C# 8.0 heeft null-referentietypen geïntroduceerd, waarbij je kunt aangeven dat een referentietype mogelijk null kan zijn of altijd niet-null is. Misschien denkt u: "Ik dacht dat alle verwijzingstypen nullable zijn!" Je bent niet verkeerd, en dat zijn ze. Met deze functie kunt u uw intentie uitdrukken, die de compiler vervolgens probeert af te dwingen. Dezelfde T? syntaxis geeft aan dat een verwijzingstype bedoeld is om nullable te zijn.
Bekijk het volgende C#-fragment:
#nullable enable
string first = string.Empty;
string second;
string? third;
In het voorgaande voorbeeld wordt uw intentie als volgt afgeleid door de compiler:
-
firstis nooitnullomdat het zeker is toegewezen. -
secondmag nooit zijnnull, ook al is het in eerste instantienull. Evaluerensecondvoordat u een waarde toewijst, resulteert in een compilerwaarschuwing omdat deze niet geïnitialiseerd is. -
thirdmisschien welnull. Het kan bijvoorbeeld wijzen naar een , maar het kan ook wijzen naarSystem.String. Een van deze variaties is acceptabel. De compiler helpt u door u te waarschuwen als u de dereferentiethirdzonder eerst te controleren of deze geen null-waarde is.
Belangrijk
Als u de functie voor null-verwijzingstypen wilt gebruiken zoals hierboven wordt weergegeven, moet deze zich in een null-context bevinden. Dit wordt beschreven in de volgende sectie.
Null-context
Met null-contexten kunt u nauwkeurig bepalen hoe de compiler referentietypevariabelen interpreteert. Er zijn vier mogelijke null-contexten:
-
disable: De compiler gedraagt zich op dezelfde manier als C# 7.3 en eerder. -
enable: De compiler maakt alle null-verwijzingsanalyse en alle taalfuncties mogelijk. -
warnings: De compiler voert alle null-analyses uit en geeft waarschuwingen wanneer code mogelijknullkan dereferenceren. -
annotations: de compiler voert geen null-analyse uit en geeft geen waarschuwingen wanneer de codenullzou kunnen dereferenceren, maar u kunt uw code nog steeds annoteren met null-referentietypen?en null-forgiving-operators (!).
Deze module is beperkt tot ofwel disable of enable nul-toelaatbare contexten. Raadpleeg voor meer informatie de referentietypen Nullable: Nullable contexten.
Null-verwijzingstypen inschakelen
Voeg in het C#-projectbestand (.csproj) een onderliggend <Nullable> knooppunt toe aan het <Project> element (of voeg toe aan een bestaand <PropertyGroup>). Hiermee wordt de enable null-context toegepast op het hele project.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- Omitted for brevity -->
</Project>
U kunt ook een null-context toepassen op een C#-bestand met behulp van een compilerrichtlijn.
#nullable enable
De voorgaande C#-compilerrichtlijn is functioneel gelijk aan de projectconfiguratie, maar is beperkt tot het bestand waarin deze zich bevindt. Zie Null-referentietypen voor meer informatie: Null-contexten (docs)
Belangrijk
De null-context is standaard ingeschakeld in het .csproj-bestand in alle C#-projectsjablonen die beginnen met .NET 6.0 en hoger.
Wanneer de null-context is ingeschakeld, krijgt u nieuwe waarschuwingen. Bekijk het vorige FooBar voorbeeld, dat twee waarschuwingen bevat wanneer deze worden geanalyseerd in een nullable context:
De
FooBar fooBar = null;regel geeft een waarschuwing voor denulltoewijzing: C# Waarschuwing CS8600: null-letterwaarde of mogelijke null-waarde converteren naar een niet-nulwaarde-type.De
_ = fooBar.ToString();regel heeft ook een waarschuwing. Deze keer maakt de compiler zich zorgen datfooBarmogelijk null kan zijn: C#-waarschuwing CS8602: Dereferencing van een mogelijk null-verwijzing.
Belangrijk
Er is geen gegarandeerde null-veiligheid, zelfs als u op alle waarschuwingen reageert en deze elimineert. Er zijn enkele beperkte scenario's die de analyse van de compiler doorstaan, maar leiden tot een runtime NullReferenceException.
Samenvatting
In deze les hebt u geleerd om een nullable context in C# in te schakelen om u te beschermen tegen NullReferenceException. In de volgende eenheid leert u meer over het expliciet uitdrukken van uw intentie in een nullable context.