A nullability ismertetése

Befejeződött

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 nullhivatkozik: . 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 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 intDateTime Ha ezeket a típusokat érték nélkül inicializálják, azok visszaállnak az értékükre default . Egy ilyen inteset esetén ez a következő 0. DateTimeEgy, 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ípus string deklarálva lett, de nem történt hozzárendelés.
  • second deklarálásakor lesz hozzárendelve string.Empty . Az objektumnak soha nem volt hozzárendelése null .
  • third annak ellenére, 0 hogy nincs hozzárendelve. Ez egy struct (érték típusú) és default értéke 0.
  • datenem inicializálódik, de default értéke .System.DateTime.MinValue

A C# 2.0-tól kezdve null értékű értéktípusokat definiálhat 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árendelve null .
  • third értéke null a defaultNullable<int>nullkövetkező.
  • fourth az a 0 kifejezés, amely meghívja new() a Nullable<int> konstruktort, és int alapértelmezés szerint az 0 .

A C# 8.0 null értékű referenciatípusokat vezetett 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 :

  • firstsoha nemmert határozottan hozzárendelték.
  • second soha nem kell , nullannak ellenére, hogy eredetileg null. Az érték hozzárendelése előtt történő kiértékelés second fordítói figyelmeztetést eredményez, mivel az nem inicializálódik.
  • third nulllehet . Előfordulhat például , hogy egy System.String, de lehet, hogy a null. Bármelyik változat elfogadható. A fordító azzal segít, ha figyelmeztetést ad arról, ha a halasztás third 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ülhet null.
  • annotations: A fordító nem végez nullelemzést, és nem ad ki figyelmeztetést, ha a kód elferdülhet null, 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 disableenable 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:

  1. A FooBar fooBar = null; sor figyelmeztetést tartalmaz a null 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.

    Képernyőkép a C# CS8600 figyelmeztetéséről: Null literál vagy lehetséges null érték konvertálása nem null értékűre.

  2. 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.

    A C# CS8602 figyelmeztetésének képernyőképe: 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 NullReferenceExceptioneredmé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.