Typy referencyjne dopuszczające wartość null

W kontekście nieświadomym wartości null wszystkie typy odwołań były dopuszczane do wartości null. Typy odwołań dopuszczające wartość null odwołują się do grupy funkcji włączonej w kontekście obsługującym wartość null, które minimalizują 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 Learn dotyczącym bezpieczeństwa z możliwością 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 wartości i int są reprezentowane odpowiednio przez System.Nullable<System.Int32> elementy i System.Int32.

Typy referencyjne dopuszczane do wartości null to funkcja czasu kompilacji. Oznacza to, że obiekty wywołujące mogą ignorować ostrzeżenia, celowo użyć null jako argumentu metody oczekującej odwołania innego niż null. Autorzy bibliotek powinni uwzględnić kontrole środowiska uruchomieniowego pod kątem wartości argumentów o wartości null. Jest to preferowana ArgumentNullException.ThrowIfNull 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 Entity Framework Core Fundamentals: Working with Nullable Reference Types (Podstawy platformy Entity Framework: praca z typami referencyjnymi dopuszczanymi wartości null).

Typy ogólne

Typy ogólne wymagają szczegółowych reguł do obsługi T? dla dowolnego parametru Ttypu . Reguły są koniecznie szczegółowe ze względu na historię i inną implementację dla typu wartości dopuszczanej do wartości null i typu odwołania dopuszczanego do wartości null. Typy wartości dopuszczalnych wartości null są implementowane przy użyciu System.Nullable<T> struktury . Typy referencyjne dopuszczające wartość null są implementowane jako adnotacje typów, które udostępniają reguły semantyczne kompilatorowi.

  • Jeśli argument typu dla T jest typem referencyjnym, T? odwołuje się do odpowiedniego typu odwołania dopuszczanego do wartości null. Jeśli na przykład element ma stringwartość T , wartość T? to string?.
  • Jeśli argument type 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, element T? jest również .int
  • Jeśli argument typu dla T jest typu odwołania dopuszczające wartość null, T? odwołuje się do tego samego typu odwołania dopuszczające wartość null. Na przykład jeśli element to string?, element T? jest również wartością string?.T
  • Jeśli argument typu dla T jest typem wartości dopuszczanej do wartości null, T? odwołuje się do tego samego typu wartości dopuszczających wartość null. Na przykład jeśli element to int?, element T? jest również wartością int?.T

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

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

  • Ograniczenie class oznacza, że T musi to być typ odwołania nie dopuszczający wartości null (na przykład string). Kompilator generuje ostrzeżenie, jeśli używasz typu odwołania dopuszczającego wartość null, takiego jak string? dla elementu T.
  • Ograniczenie class? oznacza, że T musi być typem odwołania, innym niż null (string) lub typem odwołania dopuszczanym do wartości null (na 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 referencyjnym bez wartości null lub typem wartości innej niż null. Jeśli używasz typu odwołania dopuszczającego wartość null lub typu wartości dopuszczanej do wartości null dla parametru typu, kompilator generuje ostrzeżenie. Ponadto, gdy T jest typem wartości, zwracana wartość jest tym typem wartości, a nie odpowiadającym mu typem wartości dopuszczanej do wartości null.

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

Konteksty dopuszczane do wartości null

Nowe funkcje chroniące przed zgłaszaniem elementu System.NullReferenceException mogą być destrukcyjne po włączeniu w istniejącej bazie kodu:

  • Wszystkie jawnie wpisane zmienne referencyjne są interpretowane jako typy referencyjne, które nie dopuszczają wartości null.
  • Znaczenie class ograniczenia w rodzajach ogólnych zmieniło się na oznaczające typ odwołania niepustego.
  • 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ą precyzyjne sterowanie sposobem interpretowania zmiennych typu odwołania przez kompilator. Kontekst adnotacji dopuszczającego wartość null określa zachowanie kompilatora. Istnieją cztery wartości kontekstu adnotacji dopuszczanej do wartości null:

  • disable: kod jest nieznośny bez wartości null.
    • Ostrzeżenia dopuszczające wartość null są wyłączone.
    • Wszystkie zmienne typu odwołania są typami referencyjnymi dopuszczanymi wartości null.
    • Nie można zadeklarować zmiennej jako typu odwołania dopuszczanego do wartości null przy użyciu sufiksu ? w typie.
    • Możesz użyć operatora forgiving o wartości null , !ale nie ma żadnego efektu.
  • enable: kompilator włącza wszystkie analizy odwołań o wartości null i wszystkie funkcje języka.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
    • Możesz użyć sufiksu ? , aby zadeklarować typ odwołania dopuszczalny do wartości null.
    • Wszystkie inne zmienne typu odwołania są typami referencyjnymi, które nie dopuszczają wartości null.
    • Operator forgiving o wartości null pomija ostrzeżenia dotyczące możliwego przypisania do elementu null.
  • ostrzeżenia: kompilator wykonuje wszystkie analizy wartości null i emituje ostrzeżenia, gdy kod może wyłuszczyć wartość null.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
    • Użycie sufiksu w ? celu zadeklarowania typu odwołania dopuszczanego do wartości null powoduje 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żna 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 wyłuszczyć wartość null.
    • Wszystkie nowe ostrzeżenia dopuszczające wartość null są wyłączone.
    • Możesz użyć sufiksu ? , aby zadeklarować typ odwołania dopuszczalny do wartości null.
    • Wszystkie inne zmienne typu odwołania są typami referencyjnymi, które nie dopuszczają wartości null.
    • Możesz użyć operatora forgiving o wartości null , !ale nie ma żadnego efektu.

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 wyłudzenia 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 są uważane za nie null przy otwieraniu 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 w kontekście wyłączonymnieświadome wartości null. Możesz przypisać literał lub zmienną nullo wartości może mieć wartość null do zmiennej, która nie jest nieświadoma wartości null. Jednak domyślny stan zmiennej o 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ń, które nie dopuszczają 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żna 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, aby wyłączyć.
  • #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 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.

Dla 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 Rozwiązywanie problemów z ostrzeżeniami analizy
Włącz domyślna wartość projektu Rozwiązywanie problemów z ostrzeżeniami 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 szczegółową kontrolę nad diagnostyką, którą kompilator emituje dla kodu. Możesz włączyć więcej funkcji w dowolnym obszarze, który jest aktualizowany, bez wyświetlania dodatkowych ostrzeżeń, które nie są jeszcze gotowe do rozwiązania.

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 on znajdować się w dowolnym wierszu w tym komentarzu, ale blok komentarza musi być pierwszym elementem w pliku.
  3. Uruchamianie nazwy pliku przy użyciu TemporaryGeneratedFile_
  4. Zakończ nazwę pliku na . designer.cs, .generated.cs, .g.cs lub .g.i.cs.

Generatory mogą korzystać z #nullable dyrektywy preprocesora.

Domyślnie konteksty adnotacji dopuszczające wartość null i ostrzeżenia 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 aktualizacji istniejącej bazy kodu w celu używania typów referencyjnych dopuszczanych wartości null.

Znane pułapki

Tablice i struktury zawierające typy referencyjne są znanymi pułapkami w odwołaniach dopuszczających wartość null i analizą statyczną, która określa bezpieczeństwo wartości null. W obu sytuacjach odwołanie nie dopuszczające wartości null może zostać zainicjowane do nullelementu bez generowania ostrzeżeń.

Struktury

Struktura, która zawiera typy referencyjne, które nie dopuszczają wartości null, 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ń nie dopuszczające wartości null i LastName mają wartość null.

Innym bardziej typowym przypadkiem jest sytuacja, w której zajmujesz się strukturami ogólnymi. 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 znajdować null się w czasie wykonywania i jest przypisana do ciągu bez wartości null bez żadnych ostrzeżeń.

Tablice

Tablice są również znanym pułapem 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, a jego elementy są inicjowane na nullwartość . 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ż