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 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 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 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árendelve null .
  • third értéke null a default Nullable<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 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 :

  • firstsoha nemnull, mert határozottan hozzárendelték.
  • secondsoha 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 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:

  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.