Typy wartości dopuszczają wartość null (odwołanie w C#)

Typ wartości dopuszczania wartości null reprezentuje wszystkie wartości typu wartości bazowej T? i T dodatkową wartość null. Do zmiennej można na przykład przypisać dowolną z trzech następujących bool? true false wartości: , lub null . Typ wartości bazowej nie T może być typem wartości dopuszczania wartości null.

Uwaga

W języku C# 8.0 wprowadzono funkcję typów referencyjnych dopuszczanych wartością null. Aby uzyskać więcej informacji, zobacz Typy referencyjne dopuszczane wartością null. Typy wartości dopuszczają wartość null, począwszy od języka C# 2.

Każdy typ wartości dopuszczania wartości null jest wystąpieniem struktury System.Nullable<T> ogólnej. Można odwoływać się do typu wartości dopuszczania wartości null z typem bazowym w dowolnej z następujących T wymiennych form: Nullable<T> lub T? .

Typ wartości dopuszczania wartości null jest zwykle używany, gdy trzeba reprezentować niezdefiniowana wartość bazowego typu wartości. Na przykład zmienną logiczną lub bool zmienną może być tylko true zmienna lub false . Jednak w niektórych aplikacjach wartość zmiennej może być niezdefiniowana lub może jej brakować. Na przykład pole bazy danych może zawierać wartość lub lub może nie true false zawierać żadnej wartości, czyli NULL . W tym bool? scenariuszu można użyć typu .

Deklaracja i przypisanie

Ponieważ typ wartości jest niejawnie konwertowalny na odpowiedni typ wartości dopuszczanej wartością null, możesz przypisać wartość do zmiennej typu wartości dopuszczanej wartością null, tak jak w przypadku jej bazowego typu wartości. Możesz również przypisać null wartość. Na przykład:

double? pi = 3.14;
char? letter = 'a';

int m2 = 10;
int? m = m2;

bool? flag = null;

// An array of a nullable value type:
int?[] arr = new int?[10];

Wartość domyślna typu wartości dopuszczania wartości null reprezentuje wartość , czyli jest to wystąpienie, którego null Nullable<T>.HasValue właściwość zwraca wartość false .

Badanie wystąpienia typu wartości dopuszczacej wartość null

Począwszy od języka C# 7.0, można użyć is operatora z wzorcem typu, aby zbadać wystąpienie typu wartości dopuszczanej null i pobrać wartość null typu bazowego:

int? a = 42;
if (a is int valueOfA)
{
    Console.WriteLine($"a is {valueOfA}");
}
else
{
    Console.WriteLine("a does not have a value");
}
// Output:
// a is 42

Zawsze możesz użyć następujących właściwości tylko do odczytu, aby zbadać i uzyskać wartość zmiennej typu wartości dopuszczających wartość null:

W poniższym przykładzie użyto właściwości , aby sprawdzić, czy HasValue zmienna zawiera wartość przed jej wyświetleniem:

int? b = 10;
if (b.HasValue)
{
    Console.WriteLine($"b is {b.Value}");
}
else
{
    Console.WriteLine("b does not have a value");
}
// Output:
// b is 10

Można również porównać zmienną typu wartości dopuszczania wartości null z wartością zamiast używania właściwości null HasValue , jak pokazano w poniższym przykładzie:

int? c = 7;
if (c != null)
{
    Console.WriteLine($"c is {c.Value}");
}
else
{
    Console.WriteLine("c does not have a value");
}
// Output:
// c is 7

Konwersja z typu wartości dopuszczacej wartość null na typ bazowy

Jeśli chcesz przypisać wartość typu wartości dopuszczacej wartość null do zmiennej typu wartości nienadajnej wartości null, może być konieczne określenie wartości, która ma zostać przypisana, a nie null zmiennej . W tym celu użyj operatora ?? uwierzytelniania typu null (możesz również użyć metody w Nullable<T>.GetValueOrDefault(T) tym samym celu):

int? a = 28;
int b = a ?? -1;
Console.WriteLine($"b is {b}");  // output: b is 28

int? c = null;
int d = c ?? -1;
Console.WriteLine($"d is {d}");  // output: d is -1

Jeśli chcesz użyć wartości domyślnej typu wartości bazowej, a nie null wartości , użyj metody Nullable<T>.GetValueOrDefault() .

Można również jawnie rzutować typ wartości dopuszczacej wartość null na typ, który nie dopuszcza wartości null, jak pokazano w poniższym przykładzie:

int? n = null;

//int m1 = n;    // Doesn't compile
int n2 = (int)n; // Compiles, but throws an exception if n is null

W czasie uruchamiania, jeśli wartość typu wartości dopuszczania wartości null to , jawne rzutowania null zgłasza wyjątek InvalidOperationException .

Typ wartości nienadajnej do wartości null jest niejawnie konwertowany na odpowiedni typ T wartości dopuszczania wartości null T? .

Operatory podniesione

Wstępnie zdefiniowane operatory binarne i binarne lub wszelkie przeciążone operatory obsługiwane przez typ wartości są również obsługiwane przez odpowiedni typ wartości T dopuszczania wartości null T? . Te operatory, znane również jako operatory podniesione, dają, jeśli jeden lub oba operandy są ; w przeciwnym razie operator używa zawartych wartości swoich null operandów do obliczenia null wyniku. Na przykład:

int? a = 10;
int? b = null;
int? c = 10;

a++;        // a is 11
a = a * c;  // a is 110
a = a + b;  // a is null

Uwaga

W przypadku typu wstępnie zdefiniowane operatory i nie są zgodne z regułami opisanymi w tej sekcji: wynikiem oceny operatora może być wartość non-null, nawet jeśli jeden z bool? & | operandów to null . Aby uzyskać więcej informacji, zobacz sekcję Operatory logiczne dopuszczace wartość null artykułu Operatory logiczne.

W przypadku operatorów porównania , , i , jeśli jeden lub oba operandy mają wartość , wynikiem jest ; w przeciwnym razie zawarte wartości < > <= >= null false operandów są porównywane. Nie należy zakładać, że ponieważ konkretne porównanie (na przykład ) zwraca wartość , porównanie <= false odwrotne ( > ) zwraca wartość true . Poniższy przykład pokazuje, że 10 to

  • nie większe niż lub równe null
  • ani mniejsze niż null
int? a = 10;
Console.WriteLine($"{a} >= null is {a >= null}");
Console.WriteLine($"{a} < null is {a < null}");
Console.WriteLine($"{a} == null is {a == null}");
// Output:
// 10 >= null is False
// 10 < null is False
// 10 == null is False

int? b = null;
int? c = null;
Console.WriteLine($"null >= null is {b >= c}");
Console.WriteLine($"null == null is {b == c}");
// Output:
// null >= null is False
// null == null is True

W przypadku operatora równości , jeśli oba operandy mają wartość , wynik to , jeśli tylko jeden z operandów to , wynik to ; w przeciwnym razie zawarte wartości == null true operandów są null false porównywane.

W przypadku operatora nierówności, jeśli oba operandy mają wartość , wynik to , jeśli tylko jeden z operandów to , wynik to ; w przeciwnym razie zawarte wartości != null operandów są false null true porównywane.

Jeśli istnieje zdefiniowana przez użytkownika konwersja między dwoma typami wartości, można również użyć tej samej konwersji między odpowiednimi typami wartości dopuszczania wartości null.

Boxing and unboxing (Boxing i rozpakowanie)

Wystąpienie typu wartości dopuszczacej wartość null T? jest boxed w następujący sposób:

  • W HasValue przypadku false zwracania wartości zwracane jest odwołanie o wartości null.
  • Jeśli zwraca wartość , odpowiadająca wartość typu wartości bazowej jest HasValue true T boxed, a nie wystąpienie Nullable<T> .

Możesz rozpakować wartość typu wartości w polu na odpowiedni typ wartości dopuszczającej wartość T T? null, jak pokazano w poniższym przykładzie:

int a = 41;
object aBoxed = a;
int? aNullable = (int?)aBoxed;
Console.WriteLine($"Value of aNullable: {aNullable}");

object aNullableBoxed = aNullable;
if (aNullableBoxed is int valueOfA)
{
    Console.WriteLine($"aNullableBoxed is boxed int: {valueOfA}");
}
// Output:
// Value of aNullable: 41
// aNullableBoxed is boxed int: 41

Jak zidentyfikować typ wartości dopuszczanej wartością null

W poniższym przykładzie pokazano, jak określić, czy wystąpienie reprezentuje skonstruowany typ wartości null, czyli typ z System.Type System.Nullable<T> określonym parametrem typu T :

Console.WriteLine($"int? is {(IsNullable(typeof(int?)) ? "nullable" : "non nullable")} value type");
Console.WriteLine($"int is {(IsNullable(typeof(int)) ? "nullable" : "non-nullable")} value type");

bool IsNullable(Type type) => Nullable.GetUnderlyingType(type) != null;

// Output:
// int? is nullable value type
// int is non-nullable value type

Jak pokazano w przykładzie, do utworzenia wystąpienia należy użyć operatora typeof. System.Type

Jeśli chcesz określić, czy wystąpienie ma typ wartości dopuszczający wartość null, nie używaj metody w celu przetestowania wystąpienia z Object.GetType Type poprzednim kodem. W przypadku wywołania metody w wystąpieniu typu wartości dopuszczania wartości Object.GetType null wystąpienie jest boxed na wartość Object . Ponieważ boxing wystąpienia o wartości innych niż null typu wartości dopuszczających wartość null jest odpowiednikiem boxing wartości typu bazowego, zwraca wystąpienie, które reprezentuje typ bazowy typu wartości dopuszczające wartość GetType Type null:

int? a = 17;
Type typeOfA = a.GetType();
Console.WriteLine(typeOfA.FullName);
// Output:
// System.Int32

Ponadto nie używaj operatora is, aby określić, czy wystąpienie ma typ wartości null. Jak pokazano w poniższym przykładzie, nie można odróżnić typów wystąpienia typu wartości null i jego bazowego wystąpienia typu za pomocą is operatora :

int? a = 14;
if (a is int)
{
    Console.WriteLine("int? instance is compatible with int");
}

int b = 17;
if (b is int?)
{
    Console.WriteLine("int instance is compatible with int?");
}
// Output:
// int? instance is compatible with int
// int instance is compatible with int?

Możesz użyć kodu przedstawionego w poniższym przykładzie, aby określić, czy wystąpienie ma typ wartości dopuszczania wartości null:

int? a = 14;
Console.WriteLine(IsOfNullableType(a));  // output: True

int b = 17;
Console.WriteLine(IsOfNullableType(b));  // output: False

bool IsOfNullableType<T>(T o)
{
    var type = typeof(T);
    return Nullable.GetUnderlyingType(type) != null;
}

Uwaga

Metody opisane w tej sekcji nie mają zastosowania w przypadku typów referencyjnych dopuszczanych wartością null.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:

Zobacz też