Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga
W tym artykule opisano typy referencyjne dopuszczane do wartości null. Można również zadeklarować typy wartości dopuszczanych do wartości null.
Użyj typów odwołań dopuszczających wartość null w kodzie, który znajduje się w kontekście obsługującym wartość null. Typy referencyjne dopuszczające wartość null, ostrzeżenia analizy statycznej o wartości null i operator forgiving o wartości null są opcjonalnymi funkcjami językowymi. Wszystkie są domyślnie wyłączone. Kontekst dopuszczalny do wartości null można kontrolować na poziomie projektu przy użyciu ustawień kompilacji lub w kodzie przy użyciu pragmas.
Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację funkcji w publicznej wersji zapoznawczej nadchodzącej wersji językowej.
Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.
Wskazówka
Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.
Ważne
Wszystkie szablony projektów włączają kontekst dopuszczalności wartości null dla projektu. Projekty utworzone przy użyciu wcześniejszych szablonów nie zawierają tego elementu, a te funkcje są wyłączone, chyba że włączysz je w pliku projektu lub użyj pragmas.
W kontekście obsługującym wartość null:
- Musisz zainicjować zmienną typu
Todwołania o wartości innej niż null i nigdy nie można przypisać wartości, która może mieć wartośćnull. - Można zainicjować zmienną typu
T?odwołania za pomocąnullmetody lub przypisaćnullją , ale przed wyłuszczeniem należy jąnullsprawdzić. - Po zastosowaniu operatora forgiving o wartości null do zmiennej
mtypuT?, jak w ,m!zmienna jest uważana za inną niż null.
Kompilator wymusza różnice między typem odwołania nienależącym do wartości null a typem TT? odwołania dopuszczającym wartość null przy użyciu powyższych reguł. Zmienna typu T i zmienna typu T? są tym samym typem platformy .NET. W poniższym przykładzie zadeklarowany jest ciąg bez wartości null i ciąg dopuszczający wartość null, a następnie używa operatora forgiving o wartości null do przypisania wartości do ciągu, który nie może mieć wartości null:
string notNull = "Hello";
string? nullable = default;
notNull = nullable!; // null forgiveness
notNull Zmienne i nullable oba używają String typu. Ponieważ typy niepuste i dopuszczane do wartości null używają tego samego typu, nie można użyć typu odwołania dopuszczalnego wartości null w kilku lokalizacjach. Ogólnie rzecz biorąc, nie można użyć typu odwołania dopuszczanego do wartości null jako klasy bazowej ani zaimplementowanego interfejsu. Nie można użyć typu odwołania dopuszczanego do wartości null w żadnym wyrażeniu tworzenia obiektu ani testowania typu. Nie można użyć typu odwołania dopuszczanego do wartości null jako typu wyrażenia dostępu do składowej. W poniższych przykładach przedstawiono te konstrukcje:
public MyClass : System.Object? // not allowed
{
}
var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
if (thing is string? nullableString) // not allowed
Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
Console.WriteLine("error");
}
Odwołania dopuszczane do wartości null i analiza statyczna
Przykłady w poprzedniej sekcji ilustrują charakter typów odwołań dopuszczanych do wartości null. Typy referencyjne dopuszczane do wartości null nie są nowymi typami klas, ale raczej adnotacjami w istniejących typach referencyjnych. Kompilator używa tych adnotacji, aby ułatwić znalezienie potencjalnych błędów odwołania o wartości null w kodzie. Nie ma różnicy w czasie wykonywania między typem odwołania bez wartości null a typem odwołania dopuszczanym do wartości null. Kompilator nie dodaje żadnego sprawdzania środowiska uruchomieniowego pod kątem typów odwołań bez wartości null. Korzyści są w analizie czasu kompilacji. Kompilator generuje ostrzeżenia, które ułatwiają znajdowanie i naprawianie potencjalnych błędów null w kodzie. Zadeklarujesz intencję, a kompilator ostrzega Cię, gdy kod narusza ten zamiar.
Ważne
Adnotacje referencyjne dopuszczane do wartości null nie wprowadzają zmian zachowania, ale inne biblioteki mogą używać odbicia do tworzenia różnych zachowań środowiska uruchomieniowego dla typów odwołań dopuszczanych do wartości null i innych niż null. W szczególności program Entity Framework Core odczytuje atrybuty nullable. Interpretuje odwołanie z możliwością przyjęcia wartości null jako wartość opcjonalną i odwołanie niedopuszczalne do wartości null jako wymaganą wartość.
W kontekście z obsługą wartości null kompilator wykonuje analizę statyczną zmiennych dowolnego typu odwołania, zarówno dopuszczaną do wartości null, jak i niepustą. Kompilator śledzi stan null każdej zmiennej referencyjnej jako nie null lub być może null. Domyślny stan odwołania niezwiązanego z wartością null nie jest zerowy. Domyślnym stanem odwołania dopuszczanego do wartości null jest być może wartość null.
Typy odwołań bez wartości null powinny być zawsze bezpieczne do wyłudzenia, ponieważ ich stan null nie ma wartości null. Aby wymusić daną regułę, kompilator wystawia ostrzeżenia, jeśli typ odwołania niezwiązany z wartością null nie jest inicjowany do wartości innej niż null. Należy przypisać zmienne lokalne, w których je deklarujesz. Każde pole musi mieć przypisaną wartość niepustą w inicjatorze pola lub każdym konstruktorze. Kompilator zgłasza ostrzeżenia, gdy odwołanie niezwiązane z wartością null jest przypisane do odwołania, którego stan może ma wartość null. Ogólnie rzecz biorąc, odwołanie nie dopuszczające wartości null nie ma wartości null i podczas wyłudywania tych zmiennych nie są wyświetlane żadne ostrzeżenia.
Uwaga
Jeśli przypiszesz wyrażenie może mieć wartość null do typu odwołania innego niż null, kompilator generuje ostrzeżenie. Kompilator generuje następnie ostrzeżenia dla tej zmiennej, dopóki nie zostanie przypisane do wyrażenia innego niż null .
Można zainicjować lub przypisać null do typów odwołań dopuszczanych do wartości null. W związku z tym analiza statyczna musi określić, że zmienna nie ma wartości null , zanim zostanie wyłuszona. Jeśli odwołanie dopuszczające wartość null jest określane jako możliwe do wartości null, przypisanie go do zmiennej referencyjnej bez wartości null spowoduje wygenerowanie ostrzeżenia kompilatora. W poniższej klasie przedstawiono przykłady tych ostrzeżeń:
public class ProductDescription
{
private string shortDescription;
private string? detailedDescription;
public ProductDescription() // Warning! shortDescription not initialized.
{
}
public ProductDescription(string productDescription) =>
this.shortDescription = productDescription;
public void SetDescriptions(string productDescription, string? details=null)
{
shortDescription = productDescription;
detailedDescription = details;
}
public string GetDescription()
{
if (detailedDescription.Length == 0) // Warning! dereference possible null
{
return shortDescription;
}
else
{
return $"{shortDescription}\n{detailedDescription}";
}
}
public string FullDescription()
{
if (detailedDescription == null)
{
return shortDescription;
}
else if (detailedDescription.Length > 0) // OK, detailedDescription can't be null.
{
return $"{shortDescription}\n{detailedDescription}";
}
return shortDescription;
}
}
Poniższy fragment kodu pokazuje, gdzie kompilator emituje ostrzeżenia podczas korzystania z tej klasy:
string shortDescription = default; // Warning! non-nullable set to null;
var product = new ProductDescription(shortDescription); // Warning! static analysis knows shortDescription maybe null.
string description = "widget";
var item = new ProductDescription(description);
item.SetDescriptions(description, "These widgets will do everything.");
W poprzednich przykładach pokazano, jak analiza statyczna kompilatora określa stan null zmiennych referencyjnych. Kompilator stosuje reguły języka do sprawdzania wartości null i przypisań w celu informowania o analizie. Kompilator nie może podjąć założeń dotyczących semantyki metod lub właściwości. Jeśli wywołasz metody, które wykonują kontrole wartości null, kompilator nie może wiedzieć, że te metody wpływają na stan null zmiennej. Możesz dodać atrybuty do interfejsów API, aby poinformować kompilator o semantyce argumentów i zwracanych wartości. Wiele typowych interfejsów API w bibliotekach .NET ma te atrybuty. Na przykład kompilator poprawnie interpretuje IsNullOrEmpty jako sprawdzanie wartości null. Aby uzyskać więcej informacji na temat atrybutów, które mają zastosowanie do analizy statycznej stanu null, zobacz artykuł dotyczący atrybutów dopuszczających wartość null.
Kontekst dopuszczany do wartości null
Kontekst dopuszczający wartość null określa, w jaki sposób kompilator obsługuje adnotacje typu odwołania dopuszczające wartość null i jakie ostrzeżenia są generowane podczas statycznej analizy stanu null. Kontekst dopuszczający wartość null zawiera dwie flagi: ustawienie adnotacji oraz ustawienie ostrzeżenia .
Zarówno ustawienia adnotacji , jak i ustawienia ostrzeżeń są domyślnie wyłączone dla istniejących projektów. Począwszy od .NET 6 (C# 10), obie flagi są domyślnie włączone dla projektów new. Powodem istnienia dwóch odrębnych flag dla kontekstu dopuszczającego wartość null jest ułatwienie migracji dużych projektów, które powstały przed wprowadzeniem typów odniesienia dopuszczających wartość null.
W przypadku małych projektów można włączyć typy odwołań dopuszczające wartości null, naprawić ostrzeżenia i kontynuować. Jednak w przypadku większych projektów i rozwiązań wieloprojektowych proces ten może wygenerować dużą liczbę ostrzeżeń. Należy użyć dyrektyw preprocesora, aby włączać typy odwołań dopuszczające wartość null dla każdego pliku, gdy rozpoczynasz korzystanie z tych typów. Nowe funkcje chroniące przed rzuceniem System.NullReferenceException mogą mieć destrukcyjny wpływ po włączeniu w istniejącej bazie kodu.
- Wszystkie jawnie wpisane zmienne referencyjne są interpretowane jako typy referencyjne, które nie mogą być dopuszczane do wartości null.
- Znaczenie
classograniczenia w rodzajach ogólnych zmieniło się na oznaczające typ odwołania niezwiązany z wartością null. - Nowe ostrzeżenia są generowane z powodu tych nowych reguł.
Kontekst adnotacji nullable określa zachowanie kompilatora. Istnieją cztery kombinacje ustawień kontekstu dopuszczających wartości null dla .
-
oboje wyłączone: kod nie uwzględnia wartości null.
Wyłącz pasuje do zachowania sprzed włączenia typów odwołań dopuszczanych do wartości null, z wyjątkiem tego, że nowa składnia powoduje wygenerowanie ostrzeżeń zamiast błędów.
- Ostrzeżenia dopuszczające wartość null są wyłączone.
- Wszystkie zmienne typu odwołania są typami referencyjnymi dopuszczającymi wartość null.
- Użycie sufiksu
?do zadeklarowania typu odwołania dopuszczającego wartość null powoduje ostrzeżenie. - Możesz użyć operatora null-forgiving,
!, ale nie ma żadnego efektu.
-
oba włączone: kompilator włącza analizę odwołań zerowych i wszystkie funkcje językowe.
- Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
- Można użyć sufiksu
?, aby zadeklarować typ odwołania, który może przyjmować wartość null. - Zmienne typu odwołania bez sufiksu
?są typami referencyjnymi nie dopuszczającymi wartości null. - Operator ignorujący wartość null pomija ostrzeżenia dotyczące możliwego odwołania się do
null.
-
ostrzeżenie włączone: kompilator dokonuje analizy wartości null i emituje ostrzeżenia, gdy kod może odwołać się do
null.- Wszystkie nowe ostrzeżenia dopuszczające wartość null są włączone.
- Użycie sufiksu
?do zadeklarowania typu odwołania dopuszczającego wartość null powoduje ostrzeżenie. - Wszystkie zmienne typu odwołania mogą mieć wartość null. Jednak składowe mają stan null jako not-null na początku nawiasu klamrowego wszystkich metod, chyba że są zadeklarowane z sufiksem
?. - Możesz użyć operatora forgiving o wartości null,
!.
-
włączone adnotacje: kompilator nie wyświetla ostrzeżeń, gdy kod może odwołać się do
null, lub podczas przypisywania wyrażenia, które może mieć wartość null, do zmiennej nienullowej.- Wszystkie nowe ostrzeżenia dopuszczające wartość null są wyłączone.
- Można użyć sufiksu
?, aby zadeklarować typ odwołania, który może przyjmować wartość null. - Zmienne typu odwołania bez sufiksu
?są typami referencyjnymi nie dopuszczającymi wartości null. - Możesz użyć operatora null-forgiving,
!, ale nie ma żadnego efektu.
Kontekst adnotacji dopuszczający wartość null i kontekst ostrzeżenia dopuszczający wartość null dla projektu można ustawić 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 emituje. W poniższej tabeli przedstawiono dozwolone wartości i podsumowano określone konteksty.
| Context | Ostrzeżenia o dereferencji | Ostrzeżenia dotyczące przypisania | Typy odwołań |
? przyrostek |
! Operator |
|---|---|---|---|---|---|
disable |
Wyłączony | Wyłączony | Wszystkie mogą mieć wartość null | Tworzy ostrzeżenie | Nie ma żadnego efektu |
enable |
Enabled | Enabled | Nie może mieć wartości null, chyba że zadeklarowane za pomocą ? |
Deklaruje typ dopuszczający wartości null | Pomija ostrzeżenia dotyczące możliwego null przypisania |
warnings |
Enabled | Nie dotyczy | Wszystkie są dopuszczane do wartości null, ale elementy członkowskie są uznawane za niepuste podczas otwierania nawiasu klamrowego metod | Tworzy ostrzeżenie | Pomija ostrzeżenia dotyczące możliwego null przypisania |
annotations |
Wyłączony | Wyłączony | Nie może mieć wartości null, chyba że zadeklarowane za pomocą ? |
Deklaruje typ dopuszczający wartości null | Nie ma żadnego efektu |
Zmienne typu odwołania w kodzie skompilowanym w kontekście wyłączonym są nieświadome wartości null. Można przypisać literał lub zmienną null do zmiennej, która jest nieświadoma nullowalności. Jednak domyślny stan zmiennej o wartości null nie jest zerowy.
Wybierz ustawienie, które najlepiej pasuje do 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 kod może zgłaszać System.NullReferenceException. Ostrzeżenia te można rozwiązać przed zmodyfikowaniem kodu, aby włączyć typy referencyjne niezezwalające na wartość null.
- Wybierz adnotacje , aby wyrazić intencję projektu przed włączeniem ostrzeżeń.
- Wybierz Włącz dla nowych projektów i aktywnych projektów, w których chcesz zabezpieczyć się przed wyjątkami odwołań pustych.
Przykład:
<Nullable>enable</Nullable>
Możesz również użyć dyrektyw, aby ustawić te same flagi w dowolnym miejscu w kodzie źródłowym. Te dyrektywy są najbardziej przydatne podczas migrowania dużej bazy kodu.
-
#nullable enable: ustawia flagi adnotacji i ostrzeżeń, aby włączyć. -
#nullable disable: ustawia flagi adnotacji i ostrzeżeń, aby wyłączyć. -
#nullable restore: przywraca flagę adnotacji i flagę ostrzeżenia do ustawień projektu. -
#nullable disable warnings: ustawia flagę ostrzeżenia, aby ją wyłączyć. -
#nullable enable warnings: ustawia flagę ostrzeżenia, aby ją włączyć. -
#nullable restore warnings: przywraca flagę ostrzeżenia do ustawień projektu. -
#nullable disable annotations: ustawia flagę adnotacji, aby ją wyłączyć. -
#nullable enable annotations: ustawia flagę adnotacji, aby ją włączyć. -
#nullable restore annotations: przywraca flagę adnotacji do ustawień projektu.
W przypadku dowolnego wiersza kodu można ustawić dowolną z następujących kombinacji:
| Flaga ostrzeżenia | Flaga adnotacji | Użycie |
|---|---|---|
| domyślna wartość projektu | domyślna wartość projektu | Wartość domyślna |
| włączyć | wyłączyć | Naprawianie ostrzeżeń dotyczących analizy |
| włączyć | domyślna wartość projektu | Naprawianie ostrzeżeń dotyczących analizy |
| domyślna wartość projektu | włączyć | Dodaj adnotacje typu |
| włączyć | włączyć | Kod został już zmigrowany |
| wyłączyć | włączyć | Dodawanie adnotacji do kodu przed naprawieniem ostrzeżeń |
| wyłączyć | wyłączyć | Dodawanie starszego kodu do zmigrowanego projektu |
| domyślna wartość projektu | wyłączyć | Rzadko |
| wyłączyć | domyślna wartość projektu | Rzadko |
Te dziewięć kombinacji zapewnia precyzyjną kontrolę nad diagnostyką emitowaną przez kompilator kodu. Możesz włączyć więcej funkcji w dowolnym obszarze, który aktualizujesz, bez wyświetlania większej liczby 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. Ten warunek oznacza, że kompilator nie dodawać adnotacji do żadnych interfejsów API w wygenerowanych plikach. Kompilator nie generuje ostrzeżeń o wartości null dla wygenerowanych plików. Plik jest oznaczony jako wygenerowany na dowolny z następujących czterech sposobów:
- W pliku .editorconfig określ
generated_code = truew sekcji, która ma zastosowanie do tego pliku. - 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. - Rozpocznij nazwę pliku od TemporaryGeneratedFile_
- Zakończ nazwę pliku jako .designer.cs, .generated.cs, .g.cs lub .g.i.cs.
Generatory mogą wyrazić zgodę przy użyciu #nullable dyrektywy preprocesora.
Domyślnie flagi adnotacji dopuszczające wartość null i ostrzeżenia są wyłączone. To ustawienie domyślne oznacza, że istniejący kod jest kompilowany bez zmian i bez generowania nowych ostrzeżeń. Począwszy od .NET 6, nowe projekty obejmują element <Nullable>enable</Nullable> we wszystkich szablonach projektów, ustawiając te flagi na enabled.
Te opcje zapewniają dwie odrębne strategie aktualizacji istniejącej bazy kodu w celu używania typów odwołań dopuszczających wartości null.
Ustawianie kontekstu dopuszczalnego do wartości null
Kontekst dopuszczalny do wartości null można kontrolować na dwa sposoby. Na poziomie projektu dodaj <Nullable>enable</Nullable> ustawienie projektu. W jednym pliku źródłowym języka C# dodaj #nullable enable pragma, aby włączyć kontekst dopuszczalny do wartości null. Aby uzyskać więcej informacji, zobacz ustawianie strategii dopuszczanej do wartości null. Przed platformą .NET 6 nowe projekty używają wartości domyślnej, <Nullable>disable</Nullable>. Począwszy od platformy .NET 6, nowe projekty zawierają <Nullable>enable</Nullable> element w pliku projektu.
Typy ogólne
Jeśli używasz parametru typu , Tjako odpowiednik dopuszczający wartość null, rzeczywisty argument typu określa, T?jak ? jest interpretowany. Rozważ następującą deklarację ogólną:
public class Box<T>
{
public T Contents { get; set; }
}
Ponieważ parametr typu może oznaczać typ odwołania lub typ wartości, znaczenie parametru zależy od argumentu T? typu, który dostarcza obiekt wywołujący. W poniższych regułach opisano, co T? rozwiązuje problem, gdy T nie ma ograniczeń:
- Argument typu jest typem referencyjnym, który nie może zawierać wartości null. W przypadku
Box<string>parametruTjeststringiT?tostring?— odpowiadający typ odwołania dopuszczalny do wartości null. - Argument typu jest typem wartości. W przypadku
Box<int>parametruTi jestintT?równieżint— ten sam typ wartości. Adnotacja nie ma wpływu na typy wartości, chyba że parametr typu mastructograniczenie, w którym przypadkuT?oznacza Nullable<T> (int?). - Argument typu jest już dopuszczany do wartości null. W przypadku
Box<string?>parametruTjeststring?T?i nadal jest .string?Nie otrzymujesz typu "podwójnie dopuszczania wartości null".
Ograniczenia ograniczają, które argumenty typu są dozwolone. Umożliwiają one również przyczynę kompilatora dotyczące T sposobu użycia:
-
where T : classwymaga typu odwołania bez wartości null.Box<string>jest dozwolona;Box<string?>polecenie generuje ostrzeżenie. -
where T : class?zezwala na typ odwołania dopuszczany do wartości null lub nienależące do wartości null. Zarówno, jakBox<string>iBox<string?>są dozwolone. -
where T : structwymaga typu wartości innej niż null.Box<int>jest dozwolona;Box<int?>Nie. Z tym ograniczeniemT?wewnątrz ogólnych środków Nullable<T>— dlaBox<int>,T?jestint?. -
where T : notnullwymaga niepustego odwołania lub typu wartości.Box<string>iBox<int>są dozwolone;Box<string?>tworzy ostrzeżenie. -
where T : BaseTypewymaga typu odwołania innego niż null, który pochodzi zBaseTypeklasy . Dołącz?(where T : BaseType?), aby zezwolić również na typy pochodne dopuszczane do wartości null.
Ograniczenia pomagają kompilatorowi w sposobie użycia parametru typu ogólnego:
public static T? FirstOrDefault<T>(IEnumerable<T> source)
{
foreach (T item in source)
{
return item;
}
return default;
}
public static void RequireNotNull<T>(T value) where T : notnull
{
ArgumentNullException.ThrowIfNull(value);
}
public static void Generics()
{
string? first = FirstOrDefault<string>([]);
Console.WriteLine(first ?? "<empty>");
RequireNotNull("not null");
}
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz sekcję Typy referencyjne dopuszczane do wartości nullspecyfikacji języka C#.