Typy referencyjne dopuszczające wartość null

Przed C# 8.0 wszystkie typy odwołań były dopuszczane do wartości null. Typy odwołań dopuszczające wartość null odnoszą się do grupy funkcji wprowadzonych w języku C# 8.0, których można użyć, aby zminimalizować prawdopodobieństwo, że kod powoduje, że środowisko uruchomieniowe zgłasza błąd System.NullReferenceException. Typy referencyjne dopuszczające wartość null obejmują trzy funkcje, które ułatwiają uniknięcie tych wyjątków, w tym możliwość jawnego oznaczania typu odwołania jako dopuszczanego do wartości null:

  • Ulepszona analiza przepływu statycznego, która określa, czy zmienna może być null przed jego wyłuszczeniem.
  • Atrybuty, które dodają adnotacje do interfejsów API, aby analiza przepływu określała stan null.
  • Adnotacje zmiennych używane przez deweloperów do jawnego deklarowania zamierzonego stanu null dla zmiennej.

Analiza stanu null i adnotacje zmiennych są domyślnie wyłączone dla istniejących projektów — co oznacza, że wszystkie typy odwołań nadal mogą mieć wartość null. Począwszy od platformy .NET 6, są one domyślnie włączone dla nowych projektów. Aby uzyskać informacje na temat włączania tych funkcji przez deklarowanie kontekstu adnotacji dopuszczającego wartość null, zobacz Konteksty dopuszczające wartość null.

W pozostałej części tego artykułu opisano sposób działania tych trzech obszarów funkcji w celu wygenerowania ostrzeżeń, gdy kod może zostać wyłuszczyćnull wartość. Dereferencing zmiennej oznacza dostęp do jednego z jego elementów członkowskich przy użyciu . operatora (kropka), jak pokazano w poniższym przykładzie:

string message = "Hello, World!";
int length = message.Length; // dereferencing "message"

W przypadku wyłudzenia zmiennej, której wartość to null, środowisko uruchomieniowe zgłasza wartość System.NullReferenceException.

Możesz również zapoznać się z tymi pojęciami w naszym module szkoleniowym dotyczącym bezpieczeństwa dopuszczalnego wartości null w języku C#.

Analiza stanu null

Analiza stanunull śledzi stan null odwołań. Ta analiza statyczna emituje ostrzeżenia, gdy kod może wymykać nullsię . Te ostrzeżenia można rozwiązać, aby zminimalizować częstość występowania, gdy środowisko uruchomieniowe zgłasza błąd System.NullReferenceException. Kompilator używa analizy statycznej do określenia stanu null zmiennej. Zmienna nie ma wartości null lub może ma wartość null. Kompilator określa, że zmienna nie ma wartości null na dwa sposoby:

  1. Zmienna została przypisana do wartości, która jest znana jako nie null.
  2. Zmienna została sprawdzona względem null elementu i nie została zmodyfikowana od tego sprawdzenia.

Każda zmienna, która nie została określona przez kompilator jako wartość not-null , jest uznawana za może-null. Analiza zawiera ostrzeżenia w sytuacjach, w których można przypadkowo wyłusić null wartość. Kompilator generuje ostrzeżenia na podstawie stanu null.

  • Jeśli zmienna nie ma wartości null, ta zmienna może być bezpiecznie wyłuszona.
  • Gdy zmienna ma wartość może mieć wartość null, ta zmienna musi zostać sprawdzona, aby upewnić się, że nie null jest ona wcześniej wyłuszczana.

Rozpatrzmy następujący przykład:

string message = null;

// warning: dereference null.
Console.WriteLine($"The length of the message is {message.Length}");

var originalMessage = message;
message = "Hello, World!";

// No warning. Analysis determined "message" is not null.
Console.WriteLine($"The length of the message is {message.Length}");

// warning!
Console.WriteLine(originalMessage.Length);

W poprzednim przykładzie kompilator określa, że message jest to być może null po wydrukowaniu pierwszego komunikatu. Nie ma ostrzeżenia dla drugiego komunikatu. Końcowy wiersz kodu generuje ostrzeżenie, ponieważ originalMessage może mieć wartość null. W poniższym przykładzie przedstawiono bardziej praktyczne zastosowanie przechodzenia drzewa węzłów do katalogu głównego, przetwarzania każdego węzła podczas przechodzenia:

void FindRoot(Node node, Action<Node> processNode)
{
    for (var current = node; current != null; current = current.Parent)
    {
        processNode(current);
    }
}

Poprzedni kod nie generuje żadnych ostrzeżeń dotyczących wyłudania zmiennej current. Analiza statyczna określa, że current nigdy nie jest wyłudzonych, gdy jest to być może null. Zmienna current jest sprawdzana przed current.Parentnull uzyskaniem dostępu i przed przekazaniem currentProcessNode do akcji. W poprzednich przykładach pokazano, jak kompilator określa stan null dla zmiennych lokalnych podczas inicjowania, przypisywania lub porównywania z null.

Analiza stanu null nie śledzi wywoływanych metod. W rezultacie pola zainicjowane w typowej metodzie pomocnika wywoływanej przez konstruktory będą generować ostrzeżenie z następującym szablonem:

Właściwość bez wartości null "name" musi zawierać wartość inną niż null podczas zamykania konstruktora.

Te ostrzeżenia można rozwiązać na jeden z dwóch sposobów: Łańcuch konstruktorów lub atrybuty dopuszczające wartość null w metodzie pomocnika. Poniższy kod przedstawia przykład każdego z nich. Klasa Person używa wspólnego konstruktora wywoływanego przez wszystkie inne konstruktory. Klasa Student ma metodę pomocnika z adnotacją z atrybutem System.Diagnostics.CodeAnalysis.MemberNotNullAttribute :


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

Uwaga

W języku C# 10 dodano szereg ulepszeń analizy określonego przypisania i stanu null. Podczas uaktualniania do języka C# 10 można znaleźć mniej ostrzeżeń dopuszczających wartość null, które są fałszywie dodatnie. Więcej informacji o ulepszeniach specyfikacji funkcji można dowiedzieć się więcej na temat określonych ulepszeń przypisania.

Analiza stanu dopuszczającego wartość null i ostrzeżenia generowane przez kompilator pomagają uniknąć błędów programu przez wyłudzenie null. Artykuł dotyczący rozwiązywania ostrzeżeń dopuszczających wartość null zawiera techniki poprawiania ostrzeżeń, które prawdopodobnie zobaczysz w kodzie.

Atrybuty podpisów interfejsu API

Analiza stanu null wymaga wskazówek od deweloperów, aby zrozumieć semantyka interfejsów API. Niektóre interfejsy API zapewniają sprawdzanie wartości null i powinny zmienić stan null zmiennej z być może null na nie null. Inne interfejsy API zwracają wyrażenia, które nie mają wartości null lub może null , w zależności od stanu null argumentów wejściowych. Rozważmy na przykład następujący kod, który wyświetla komunikat:

public void PrintMessage(string message)
{
    if (!string.IsNullOrWhiteSpace(message))
    {
        Console.WriteLine($"{DateTime.Now}: {message}");
    }
}

Na podstawie inspekcji każdy deweloper rozważy ten kod jako bezpieczny i nie powinien generować ostrzeżeń. Kompilator nie wie, że IsNullOrWhiteSpace zapewnia sprawdzanie wartości null. Atrybuty są stosowane do informowania kompilatora, który messagenie ma wartości null , jeśli i tylko wtedy, gdy IsNullOrWhiteSpace zwraca wartość false. W poprzednim przykładzie podpis zawiera wartość , NotNullWhen aby wskazać stan null :message

public static bool IsNullOrWhiteSpace([NotNullWhen(false)] string message);

Atrybuty zawierają szczegółowe informacje na temat stanu null argumentów, zwracanych wartości i elementów członkowskich wystąpienia obiektu używanego do wywoływania elementu członkowskiego. Szczegółowe informacje na temat każdego atrybutu można znaleźć w artykule referencyjnym języka dotyczącym atrybutów referencyjnych dopuszczanych do wartości null. Wszystkie interfejsy API środowiska uruchomieniowego platformy .NET zostały oznaczone adnotacjami na platformie .NET 5. Możesz ulepszyć analizę statyczną przez dodawanie adnotacji do interfejsów API w celu udostępnienia semantycznych informacji o stanie null argumentów i zwracanych wartościach.

Adnotacje zmiennej dopuszczanej do wartości null

Analiza stanu null zapewnia niezawodną analizę większości zmiennych. Kompilator potrzebuje więcej informacji na temat zmiennych członkowskich. Kompilator nie może założyć założeń dotyczących kolejności uzyskiwania dostępu do publicznych elementów członkowskich. Dostęp do każdego publicznego członka można uzyskać w dowolnej kolejności. Dowolny z dostępnych konstruktorów może służyć do inicjowania obiektu. Jeśli pole składowe może kiedykolwiek zostać ustawione na nullwartość , kompilator musi założyć, że jego stan null ma wartość może mieć wartość null na początku każdej metody.

Można użyć adnotacji, które mogą zadeklarować, czy zmienna jest typem odwołania dopuszczalnym do wartości null , czy typem odwołania bez wartości null. Te adnotacje tworzą ważne instrukcje dotyczące stanu null dla zmiennych:

  • Odwołanie nie ma mieć wartości null. Domyślny stan zmiennej referencyjnej nienależącej do wartości null. Kompilator wymusza reguły, które zapewniają, że bezpieczne jest wyłudzenie tych zmiennych bez uprzedniego sprawdzenia, czy nie ma wartości null:
    • Zmienna musi zostać zainicjowana do wartości innej niż null.
    • Zmienna nigdy nie może być przypisana do wartości null. Kompilator wystawia ostrzeżenie, gdy kod przypisuje wyrażenie może null do zmiennej, która nie powinna mieć wartości null.
  • Odwołanie może mieć wartość null. Domyślnym stanem zmiennej referencyjnej dopuszczanej do wartości null jest być może null. Kompilator wymusza reguły, aby upewnić się, że prawidłowo sprawdzono null odwołanie:
    • Zmienna może zostać wyłuszona tylko wtedy, gdy kompilator może zagwarantować, że wartość nie nulljest .
    • Te zmienne mogą być inicjowane z wartością domyślną null i mogą być przypisane do wartości null w innym kodzie.
    • Kompilator nie wyświetla ostrzeżeń, gdy kod przypisuje wyrażenie może mieć wartość null do zmiennej, która może mieć wartość null.

Każda zmienna referencyjna, która nie ma mieć nullstanu null, nie ma wartości null. Każda zmienna referencyjna, która początkowo może mieć nullstan nullmoże mieć wartość null.

Typ odwołania dopuszczalny do wartości null jest zanotowany przy użyciu tej samej składni co typy wartości dopuszczającej wartość null: jest ? dołączany do typu zmiennej. Na przykład następująca deklaracja zmiennej zmiennej reprezentuje zmienną ciągu dopuszczaną do wartości null: name

string? name;

Każda zmienna, w ? której nie jest dołączana do nazwy typu, jest typem referencyjnym bez wartości null. Obejmuje to wszystkie zmienne typu odwołania w istniejącym kodzie po włączeniu tej funkcji. Jednak wszelkie niejawnie wpisane zmienne lokalne (zadeklarowane przy użyciu var) są typami referencyjnymi dopuszczanymi wartości null. Jak pokazano w poprzednich sekcjach, analiza statyczna określa stan null zmiennych lokalnych, aby określić, czy są one być może null.

Czasami należy zastąpić ostrzeżenie, gdy wiadomo, że zmienna nie ma wartości null, ale kompilator określa jego stan null może mieć wartość null. Użyj operatora !forgiving o wartości null po nazwie zmiennej, aby wymusić, że stan nullnie ma wartości null. Jeśli na przykład wiesz, że zmienna name nie null jest, ale kompilator wystawia ostrzeżenie, możesz napisać następujący kod, aby zastąpić analizę kompilatora:

name!.Length;

Typy odwołań dopuszczające wartość null i typy wartości dopuszczających wartość null zapewniają podobną koncepcję semantyczną: zmienna może reprezentować wartość lub obiekt albo może to być nullzmienna . Jednak typy referencyjne dopuszczane do wartości null i typy wartości dopuszczanych do wartości null są implementowane inaczej: typy wartości dopuszczalnych wartości null są implementowane przy użyciu , System.Nullable<T>a typy odwołań dopuszczane do wartości null są implementowane przez atrybuty odczytywane przez kompilator. Na przykład string? i string są reprezentowane przez ten sam typ: System.String. int? Jednak i int są reprezentowane odpowiednio przez System.Nullable<System.Int32> i , System.Int32.

Typy odwołań dopuszczane do wartości null to funkcja czasu kompilacji. Oznacza to, że osoby wywołujące mogą ignorować ostrzeżenia, celowo używać null jako argumentu do metody, która oczekuje odwołania niezwiązanego z wartością null. Autorzy bibliotek powinni uwzględniać testy środowiska uruchomieniowego względem wartości argumentów null. Jest ArgumentNullException.ThrowIfNull to preferowana opcja sprawdzania parametru względem wartości null w czasie wykonywania.

Ważne

Włączenie adnotacji dopuszczających wartość null może zmienić sposób określania, w jaki sposób platforma Entity Framework Core określa, czy element członkowski danych jest wymagany. Więcej szczegółów można znaleźć w artykule Dotyczącym podstaw platformy Entity Framework Core: Praca z typami referencyjnymi dopuszczanymi wartościami null.

Typy ogólne

Typy ogólne wymagają szczegółowych reguł obsługi T? dla dowolnego parametru Ttypu . Reguły są koniecznie szczegółowe z powodu historii i innej implementacji dla typu wartości dopuszczalnej wartości null i typu odwołania dopuszczanego do wartości null. Typy wartości dopuszczalnych wartości są implementowane przy użyciu System.Nullable<T> struktury . Typy odwołań dopuszczające wartość null są implementowane jako adnotacje typu, które zapewniają reguły semantyczne kompilatorowi.

W języku C# 8.0 użycie T? bez ograniczenia T nie structclass zostało skompilowane. Umożliwiło to kompilatorowi wyraźną interpretację T? . To ograniczenie zostało usunięte w języku C# 9.0, definiując następujące reguły dla nieokreślonego parametru Ttypu :

  • Jeśli argument typu dla T jest typem referencyjnym, T? odwołuje się do odpowiedniego typu odwołania dopuszczalnego wartości null. Jeśli na przykład T element to string, T? to jest .string?
  • Jeśli argument typu dla T jest typem wartości, T? odwołuje się do tego samego typu wartości, T. Jeśli na przykład T element to int, T? element jest również elementem int.
  • Jeśli argument typu dla T jest typem odwołania dopuszczalnym do wartości null, T? odwołuje się do tego samego typu odwołania dopuszczalnego wartości null. Jeśli na przykład T element to string?, T? jest to również string?.
  • Jeśli argument typu dla T jest typem wartości dopuszczających wartość null, T? odwołuje się do tego samego typu wartości dopuszczających wartość null. Jeśli na przykład T element to int?, T? jest to również int?.

W przypadku zwracanych wartości T? jest równoważne [MaybeNull]Twartościom ; dla wartości T? argumentów jest równoważna [AllowNull]Twartościom . Aby uzyskać więcej informacji, zobacz artykuł Atrybuty analizy stanu null w dokumentacji językowej.

Możesz określić różne zachowanie przy użyciu ograniczeń:

  • Ograniczenie class oznacza, że T musi być niepustym typem odwołania (na przykład string). Kompilator generuje ostrzeżenie, jeśli używasz typu odwołania dopuszczanego wartości null, takiego jak string? dla Telementu .
  • Ograniczenie class? oznacza, że T musi być typem odwołania, innym niż null () lub typem odwołania dopuszczanym do wartości null (stringna przykład string?). Gdy parametr typu jest typem odwołania dopuszczalnym do wartości null, takim jak string?, wyrażenie T? odwołań, które to samo typu odwołania dopuszczające wartość null, takie jak string?.
  • Ograniczenie notnull oznacza, że T musi być typem odwołania bez wartości null lub typem wartości bez wartości null. Jeśli używasz typu odwołania dopuszczanego wartości null lub typu wartości null dla parametru typu, kompilator generuje ostrzeżenie. Ponadto, gdy T jest typem wartości, zwracana wartość jest typem wartości, a nie odpowiadającym mu typem wartości null.

Te ograniczenia pomagają dostarczyć więcej informacji do kompilatora na temat T sposobu użycia. Pomaga to, gdy deweloperzy wybierają typ , Ti zapewnia lepszą analizę stanu null , gdy jest używane wystąpienie typu ogólnego.

Konteksty dopuszczane do wartości null

Nowe funkcje, które chronią przed zgłaszaniem elementu System.NullReferenceException , mogą być zakłócane po włączeniu w istniejącej bazie kodu:

  • Wszystkie jawnie wpisane zmienne referencyjne są interpretowane jako typy odwołań nienależące do wartości null.
  • Znaczenie class ograniczenia w rodzajach ogólnych zmieniło się tak, aby oznaczało niepusty typ odwołania.
  • Nowe ostrzeżenia są generowane z powodu tych nowych reguł.

Musisz jawnie wyrazić zgodę na korzystanie z tych funkcji w istniejących projektach. Zapewnia to ścieżkę migracji i zachowuje zgodność z poprzednimi wersjami. Konteksty dopuszczane do wartości null umożliwiają szczegółową kontrolę sposobu interpretowania zmiennych typu odwołania przez kompilator. Kontekst adnotacji dopuszczalny do wartości null określa zachowanie kompilatora. Istnieją cztery wartości kontekstu adnotacji z możliwością wartości null:

  • wyłącz: kompilator zachowuje się podobnie do języka C# 7.3 i starszych:
    • Ostrzeżenia dopuszczające wartość null są wyłączone.
    • Wszystkie zmienne typu odwołania są typami referencyjnymi dopuszczanymi wartościami null.
    • Nie można zadeklarować zmiennej jako typu odwołania dopuszczalnego wartości null przy użyciu sufiksu ? w typie.
    • Możesz użyć operatora forgiving o wartości null, !ale nie ma wpływu.
  • włącz: kompilator włącza całą analizę odwołania o wartości null i wszystkie funkcje języka.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
    • Sufiks można użyć ? do zadeklarowania typu odwołania dopuszczalnego wartości null.
    • Wszystkie inne zmienne typu odwołania są niepustymi typami referencyjnymi.
    • Operator forgiving o wartości null pomija ostrzeżenia dotyczące możliwego przypisania do nullelementu .
  • ostrzeżenia: kompilator wykonuje całą analizę wartości null i emituje ostrzeżenia, gdy kod może zostać wyłuszczyć null.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
    • Użyj sufiksu ? , aby zadeklarować typ odwołania dopuszczający wartość null, generuje ostrzeżenie.
    • Wszystkie zmienne typu odwołania mogą mieć wartość null. Jednak składowe mają stan nullnot-null dla otwierającego nawiasu klamrowego wszystkich metod, chyba że zadeklarowane z sufiksem ? .
    • Możesz użyć operatora forgiving o wartości null, !.
  • adnotacje: kompilator nie wykonuje analizy wartości null ani nie emituje ostrzeżeń, gdy kod może zostać wyłuszczyć null.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są wyłączone.
    • Sufiks można użyć ? do zadeklarowania typu odwołania dopuszczalnego wartości null.
    • Wszystkie inne zmienne typu odwołania są niepustymi typami referencyjnymi.
    • Możesz użyć operatora forgiving o wartości null, !ale nie ma wpływu.

Kontekst adnotacji dopuszczający wartość null i kontekst ostrzeżenia dopuszczający wartość null można ustawić dla projektu przy użyciu <Nullable> elementu w pliku csproj . Ten element konfiguruje sposób, w jaki kompilator interpretuje wartość null typów i jakie ostrzeżenia są emitowane. W poniższej tabeli przedstawiono dozwolone wartości i podsumowano określone konteksty.

Kontekst Ostrzeżenia dotyczące odroczenia Ostrzeżenia dotyczące przypisania Typy odwołań ? Sufiks ! Operator
disable Disabled Disabled Wszystkie są dopuszczane do wartości null Nie można użyć Nie ma wpływu
enable Enabled (Włączony) Enabled (Włączony) Bez wartości null, chyba że zadeklarowane za pomocą polecenia ? Deklaruje typ dopuszczalny do wartości null Pomija ostrzeżenia dotyczące możliwego null przypisania
warnings Enabled (Włączony) Nie dotyczy Wszystkie są dopuszczane do wartości null , ale elementy członkowskie nie są traktowane jako null podczas otwierania nawiasu klamrowego metod Tworzy ostrzeżenie Pomija ostrzeżenia dotyczące możliwego null przypisania
annotations Disabled Disabled Bez wartości null, chyba że zadeklarowane za pomocą polecenia ? Deklaruje typ dopuszczalny do wartości null Nie ma wpływu

Zmienne typu odwołania w kodzie skompilowanym przed C# 8 lub w kontekście wyłączonymnieświadome wartości null. Można przypisać literał lub zmienną nullmoże mieć wartość null do zmiennej, która jest bezwartościowa. Jednak domyślny stan zmiennej, która nie jest nieświadoma wartości null, nie ma wartości null.

Możesz wybrać, które ustawienie jest najlepsze dla projektu:

  • Wybierz opcję wyłącz dla starszych projektów, których nie chcesz aktualizować na podstawie diagnostyki ani nowych funkcji.
  • Wybierz ostrzeżenia, aby określić, gdzie może zostać zgłoszony System.NullReferenceExceptionkod. Te ostrzeżenia można rozwiązać przed zmodyfikowaniem kodu w celu włączenia typów odwołań bez wartości null.
  • Wybierz adnotacje , aby wyrazić intencję projektu przed włączeniem ostrzeżeń.
  • Wybierz opcję Włącz dla nowych projektów i aktywnych projektów, w których chcesz chronić przed wyjątkami odwołania o wartości null.

Przykład:

<Nullable>enable</Nullable>

Możesz również użyć dyrektyw, aby ustawić te same konteksty w dowolnym miejscu w kodzie źródłowym. Są one najbardziej przydatne podczas migrowania dużej bazy kodu.

  • #nullable enable: ustawia kontekst adnotacji dopuszczający wartość null i kontekst ostrzeżenia dopuszczający wartość null, aby włączyć.
  • #nullable disable: Ustawia kontekst adnotacji dopuszczający wartość null i kontekst ostrzeżenia dopuszczający wartość null do wyłączenia.
  • #nullable restore: przywraca kontekst adnotacji dopuszczający wartość null i kontekst ostrzeżenia dopuszczający wartość null do ustawień projektu.
  • #nullable disable warnings: ustaw kontekst ostrzeżenia dopuszczający wartość null, aby wyłączyć.
  • #nullable enable warnings: ustaw kontekst ostrzeżenia dopuszczający wartość null, aby włączyć.
  • #nullable restore warnings: przywraca kontekst ostrzeżenia dopuszczający wartość null do ustawień projektu.
  • #nullable disable annotations: Ustaw kontekst adnotacji dopuszczalnej do wartości null, aby wyłączyć.
  • #nullable enable annotations: Ustaw kontekst adnotacji dopuszczalnej wartości null, aby włączyć.
  • #nullable restore annotations: przywraca kontekst ostrzeżenia adnotacji do ustawień projektu.

W przypadku dowolnego wiersza kodu można ustawić dowolną z następujących kombinacji:

Kontekst ostrzeżenia Kontekst adnotacji Zastosowanie
domyślna wartość projektu domyślna wartość projektu Domyślny
Włącz Wyłącz Naprawianie ostrzeżeń dotyczących analizy
Włącz domyślna wartość projektu Naprawianie ostrzeżeń dotyczących analizy
domyślna wartość projektu Włącz Dodawanie adnotacji typu
Włącz Włącz Kod został już zmigrowany
Wyłącz Włącz Dodawanie adnotacji do kodu przed naprawieniem ostrzeżeń
Wyłącz Wyłącz Dodawanie starszego kodu do zmigrowanego projektu
domyślna wartość projektu Wyłącz Rzadko
Wyłącz domyślna wartość projektu Rzadko

Te dziewięć kombinacji zapewnia precyzyjną kontrolę nad diagnostyką, którą kompilator emituje dla kodu. Możesz włączyć więcej funkcji w dowolnym obszarze aktualizowanym bez wyświetlania dodatkowych ostrzeżeń, które nie są jeszcze gotowe do użycia.

Ważne

Globalny kontekst dopuszczania wartości null nie ma zastosowania do wygenerowanych plików kodu. W ramach każdej strategii kontekst dopuszczalny do wartości null jest wyłączony dla dowolnego pliku źródłowego oznaczonego jako wygenerowany. Oznacza to, że wszystkie interfejsy API w wygenerowanych plikach nie są adnotacjami. Istnieją cztery sposoby oznaczania pliku jako wygenerowanego:

  1. W pliku .editorconfig określ generated_code = true w sekcji, która ma zastosowanie do tego pliku.
  2. Umieść <auto-generated> lub <auto-generated/> w komentarzu w górnej części pliku. Może to być dowolny wiersz w tym komentarzu, ale blok komentarza musi być pierwszym elementem w pliku.
  3. Uruchom nazwę pliku przy użyciu TemporaryGeneratedFile_
  4. Zakończ nazwę pliku za pomocą pliku designer.cs, .generated.cs, . g.cs lub .g.i.cs.

Generatory mogą wyrazić zgodę na korzystanie z #nullable dyrektywy preprocesora.

Domyślnie konteksty adnotacji i ostrzeżeń z możliwością wartości null są wyłączone. Oznacza to, że istniejący kod jest kompilowany bez zmian i bez generowania nowych ostrzeżeń. Począwszy od platformy .NET 6, nowe projekty zawierają <Nullable>enable</Nullable> element we wszystkich szablonach projektów.

Te opcje zapewniają dwie odrębne strategie aktualizowania istniejącej bazy kodu w celu używania typów odwołań dopuszczanych do wartości null.

Znane pułapki

Tablice i struktury, które zawierają typy odwołań, są znane pułapki w odwołaniach dopuszczających wartość null oraz analizę statyczną, która określa bezpieczeństwo wartości null. W obu sytuacjach odwołanie niezwiązane z wartością null może zostać zainicjowane na nullwartość , bez generowania ostrzeżeń.

Struktury

Struktura, która zawiera niepuste typy odwołań, umożliwia przypisywanie default jej bez żadnych ostrzeżeń. Rozpatrzmy następujący przykład:

using System;

#nullable enable

public struct Student
{
    public string FirstName;
    public string? MiddleName;
    public string LastName;
}

public static class Program
{
    public static void PrintStudent(Student student)
    {
        Console.WriteLine($"First name: {student.FirstName.ToUpper()}");
        Console.WriteLine($"Middle name: {student.MiddleName?.ToUpper()}");
        Console.WriteLine($"Last name: {student.LastName.ToUpper()}");
    }

    public static void Main() => PrintStudent(default);
}

W poprzednim przykładzie nie ma ostrzeżenia PrintStudent(default) , podczas gdy typy FirstName odwołań bez wartości null i LastName mają wartość null.

Innym bardziej typowym przypadkiem jest radzenie sobie z ogólnymi strukturami. Rozpatrzmy następujący przykład:

#nullable enable

public struct Foo<T>
{
    public T Bar { get; set; }
}

public static class Program
{
    public static void Main()
    {
        string s = default(Foo<string>).Bar;
    }
}

W poprzednim przykładzie właściwość Bar będzie w null czasie wykonywania i jest przypisana do ciągu bez wartości null bez żadnych ostrzeżeń.

Tablice

Tablice są również znanymi pułapkami w typach referencyjnych dopuszczanych do wartości null. Rozważmy następujący przykład, który nie generuje żadnych ostrzeżeń:

using System;

#nullable enable

public static class Program
{
    public static void Main()
    {
        string[] values = new string[10];
        string s = values[0];
        Console.WriteLine(s.ToUpper());
    }
}

W poprzednim przykładzie deklaracja tablicy pokazuje, że zawiera ciągi niepuste, podczas gdy jego elementy są inicjowane do null. Następnie zmienna s ma przypisaną null wartość (pierwszy element tablicy). Na koniec zmienna s jest wyłuszczana, powodując wyjątek środowiska uruchomieniowego.

Zobacz też