A nullability ismertetése
Ha .NET-fejlesztő, akkor valószínűleg találkozott a System.NullReferenceException. Ez futásidőben fordul elő, amikor egy null
változót elhalasztanak, vagyis amikor egy változót futásidőben értékelnek ki, de a változó a következőre null
hivatkozik: . Ez a kivétel messze a .NET-ökoszisztémában leggyakrabban előforduló kivétel. A létrehozója null
, Sir Tony Hoare, utal, mint null
a "milliárd dolláros hiba."
Az alábbi példában a változó hozzá FooBar
van rendelve null
, és azonnal dereferens lesz, így a probléma a következő:
// 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);
A problémát fejlesztőként sokkal nehezebb észlelni, ha az alkalmazások mérete és összetettsége növekszik. Az ilyen lehetséges hibák észlelése egy eszközkezelő feladat, és a C#-fordító itt segít.
Null biztonság meghatározása
A null biztonság kifejezés a null értékű típusokra jellemző funkciók készletét határozza meg, amelyek segítenek csökkenteni a lehetséges NullReferenceException
előfordulások számát.
Az előző FooBar
példát figyelembe véve elkerülheti ezt úgy NullReferenceException
, hogy ellenőrzi, hogy a változó a fooBar
halasztás előtt volt-e null
:
// 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);
Az ilyen forgatókönyvek azonosításához a fordító képes a kód szándékára következtetni, és kikényszeríteni a kívánt viselkedést. Ez azonban csak akkor történik meg, ha engedélyezve van egy null értékű környezet . A null értékű környezet megvitatása előtt ismertessük a lehetséges null értékű típusokat.
Null értékű típusok
A C# 2.0 előtt csak a hivatkozástípusok voltak null értékűek. Az olyan értéktípusok, mint például int
DateTime
a nem.null
Ha ezeket a típusokat érték nélkül inicializálják, azok visszaállnak az értékükre default
. Egy ilyen int
eset esetén ez a következő 0
. DateTime
Egy, ez DateTime.MinValue
.
A kezdeti értékek nélkül példányosított referenciatípusok eltérően működnek. Az default
összes referenciatípus értéke .null
Vegye figyelembe a következő C#-kódrészletet:
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
Az előző példában:
first
azért van,null
mert a referenciatípusstring
deklarálva lett, de nem történt hozzárendelés.second
deklarálásakor lesz hozzárendelvestring.Empty
. Az objektumnak soha nem volt hozzárendelésenull
.third
annak ellenére,0
hogy nincs hozzárendelve. Ez egystruct
(érték típusú) ésdefault
értéke0
.date
nem inicializálódik, dedefault
értéke .System.DateTime.MinValue
A C# 2.0-tól kezdve null értékű értéktípusokat definiálhat a (vagy T?
rövidített) használatával Nullable<T>
. Ez lehetővé teszi, hogy az értéktípusok null értékűek legyenek. Vegye figyelembe a következő C#-kódrészletet:
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
Az előző példában:
first
az az oka,null
hogy a null értékű típus nem inicializálódott.second
deklarálásakor lesz hozzárendelvenull
.third
értékenull
adefault
Nullable<int>
null
következő.fourth
az a0
kifejezés, amely meghívjanew()
aNullable<int>
konstruktort, ésint
alapértelmezés szerint az0
.
A C# 8.0 null értékű referenciatípusokat vezetett be, ahol kifejezheti szándékát, hogy egy referenciatípus lehet null
vagy mindig nemnull
. Lehet, hogy arra gondol, "Azt hittem, minden referenciatípus null értékű!" Nem tévedsz, és ők is. Ez a funkció lehetővé teszi a szándék kifejezését, amelyet a fordító ezután megpróbál kikényszeríteni. Ugyanez a T?
szintaxis azt fejezi ki, hogy egy hivatkozástípus null értékű.
Vegye figyelembe a következő C#-kódrészletet:
#nullable enable
string first = string.Empty;
string second;
string? third;
Az előző példában szereplő fordító a következő módon következtet a szándékra :
first
soha nemnull
, mert határozottan hozzárendelték.second
soha nem kell ,null
annak ellenére, hogy eredetilegnull
. Az érték hozzárendelése előtt történő kiértékeléssecond
fordítói figyelmeztetést eredményez, mivel az nem inicializálódik.third
null
lehet . Előfordulhat például , hogy egySystem.String
, de lehet, hogy anull
. Bármelyik változat elfogadható. A fordító azzal segít, ha figyelmeztetést ad arról, ha a halasztásthird
nem null értékű.
Fontos
A fent látható null értékű hivatkozástípusok funkció használatához null értékű környezetben kell lennie. Ezt a következő szakaszban találja.
Null értékű környezet
A null értékű környezetek lehetővé teszik a referenciatípus-változók értelmezésének részletes szabályozását. Négy lehetséges null értékű környezet létezik:
disable
: A fordító a C# 7.3-hoz és korábbihoz hasonlóan viselkedik.enable
: A fordító lehetővé teszi az összes nullhivatkozás-elemzést és az összes nyelvi funkciót.warnings
: A fordító végrehajtja az összes null elemzést, és figyelmeztetéseket ad ki, amikor a kód elferdülhetnull
.annotations
: A fordító nem végez nullelemzést, és nem ad ki figyelmeztetést, ha a kód elferdülhetnull
, de a kódot null értékű hivatkozástípusokkal?
és null-megbocsátó operátorokkal (!
) is megjegyzésekkel láthatja el.
Ez a modul hatóköre vagy disable
enable
null értékű környezetekre terjed ki. További információ: Null értékű hivatkozástípusok: Null értékű környezetek.
Null értékű hivatkozástípusok engedélyezése
A C# projektfájlban (.csproj) adjon hozzá egy gyermekcsomópontot <Nullable>
az <Project>
elemhez (vagy fűzze hozzá egy meglévőhöz <PropertyGroup>
). Ez a teljes projektre alkalmazza a enable
null értékű környezetet.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- Omitted for brevity -->
</Project>
Másik lehetőségként a C#-fájlok null értékű környezetét is hatókörbe helyezheti egy fordítóirányelv használatával.
#nullable enable
Az előző C#-fordító irányelv funkcionálisan egyenértékű a projektkonfigurációval, de annak a fájlnak a hatóköre, amelyben található. További információ: Null értékű referenciatípusok: Null értékű környezetek (dokumentumok)
Fontos
A null értékű környezet alapértelmezés szerint engedélyezve van a .csproj fájlban a .NET 6.0 és újabb verziójú C# projektsablonokban.
Ha a null értékű környezet engedélyezve van, új figyelmeztetések jelennek meg. Vegyük az előző FooBar
példát, amely két figyelmeztetést tartalmaz null értékű környezetben történő elemzéskor:
A
FooBar fooBar = null;
sor figyelmeztetést tartalmaz anull
hozzárendelésre: C# FIGYELMEZTETÉS CS8600: Null literál vagy lehetséges null érték konvertálása nem null értékű típusra.A
_ = fooBar.ToString();
sornak figyelmeztetése is van. A fordítófooBar
ezúttal null értékű lehet: C# FIGYELMEZTETÉS CS8602: Lehetséges nullhivatkozás elhalasztása.
Fontos
Nincs garantált null biztonság, még akkor sem, ha reagál az összes figyelmeztetésre, és kiküszöböli az összes figyelmeztetést. Vannak korlátozott forgatókönyvek, amelyek átadják a fordító elemzését, de futásidőt NullReferenceException
eredményeznek.
Összegzés
Ebben a leckében megtanulta, hogyan engedélyezhető egy null értékű környezet a C#-ban, hogy segítsen a védelemmel szemben NullReferenceException
. A következő leckében többet is megtudhat arról, hogyan fejezheti ki szándékát egy null értékű környezetben.