可为空的值类型(C# 参考)Nullable value types (C# reference)

可为空的值类型 T? 表示其基础值类型T 的所有值,还可表示附加的 null 值。A nullable value type T? represents all values of its underlying value type T and an additional null value. 例如,可以将以下三个值中的任意一个指定给 bool? 变量:truefalsenullFor example, you can assign any of the following three values to a bool? variable: true, false, or null. 基础值类型 T 本身不能是可为空的值类型。An underlying value type T cannot be a nullable value type itself.

备注

C# 8.0 引入了可为空引用类型功能。C# 8.0 introduces the nullable reference types feature. 有关详细信息,请参阅可为空引用类型For more information, see Nullable reference types. 从 C# 2 开始,提供可为空的值类型。The nullable value types are available beginning with C# 2.

任何可为空的值类型都是泛型 System.Nullable<T> 结构的实例。Any nullable value type is an instance of the generic System.Nullable<T> structure. 可使用以下任何一种可互换形式引用具有基础类型 T 的可为空值类型:Nullable<T>T?You can refer to a nullable value type with an underlying type T in any of the following interchangeable forms: Nullable<T> or T?.

需要表示基础值类型的未定义值时,通常使用可为空的值类型。You typically use a nullable value type when you need to represent the undefined value of an underlying value type. 例如,布尔值或 bool 变量只能为 truefalseFor example, a Boolean, or bool, variable can only be either true or false. 但是,在某些应用程序中,变量值可能未定义或缺失。However, in some applications a variable value can be undefined or missing. 例如,某个数据库字段可能包含 truefalse,或者它可能不包含任何值,即 NULLFor example, a database field may contain true or false, or it may contain no value at all, that is, NULL. 在这种情况下,可以使用 bool? 类型。You can use the bool? type in that scenario.

声明和赋值Declaration and assignment

由于值类型可隐式转换为相应的可为空的值类型,因此可以像向其基础值类型赋值一样,向可为空值类型的变量赋值。As a value type is implicitly convertible to the corresponding nullable value type, you can assign a value to a variable of a nullable value type as you would do that for its underlying value type. 还可分配 null 值。You also can assign the null value. 例如:For example:

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

int m2 = 10;
int? m = m2;

bool? flag = null;

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

可为空值类型的默认值表示 null,也就是说,它是其 Nullable<T>.HasValue 属性返回 false 的实例。The default value of a nullable value type represents null, that is, it's an instance whose Nullable<T>.HasValue property returns false.

检查可为空值类型的实例Examination of an instance of a nullable value type

从 C# 7.0 开始,可以将 is 运算符与类型模式 结合使用,既检查 null 的可为空值类型的实例,又检索基础类型的值:Beginning with C# 7.0, you can use the is operator with a type pattern to both examine an instance of a nullable value type for null and retrieve a value of an underlying type:

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

始终可以使用以下只读属性来检查和获取可为空值类型变量的值:You always can use the following read-only properties to examine and get a value of a nullable value type variable:

以下示例中的使用 HasValue 属性在显示值之前测试变量是否包含该值:The following example uses the HasValue property to test whether the variable contains a value before displaying it:

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

还可将可为空的值类型的变量与 null 进行比较,而不是使用 HasValue 属性,如以下示例所示:You also can compare a variable of a nullable value type with null instead of using the HasValue property, as the following example shows:

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

从可为空的值类型转换为基础类型Conversion from a nullable value type to an underlying type

如果要将可为空值类型的值分配给不可以为 null 的值类型变量,则可能需要指定要分配的替代 null 的值。If you want to assign a value of a nullable value type to a non-nullable value type variable, you might need to specify the value to be assigned in place of null. 使用 Null 合并操作符??执行此操作(也可将 Nullable<T>.GetValueOrDefault(T) 方法用于相同的目的):Use the null-coalescing operator ?? to do that (you also can use the Nullable<T>.GetValueOrDefault(T) method for the same purpose):

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

如果要使用基础值类型的默认值来替代 null,请使用 Nullable<T>.GetValueOrDefault() 方法。If you want to use the default value of the underlying value type in place of null, use the Nullable<T>.GetValueOrDefault() method.

还可以将可为空的值类型显式强制转换为不可为 null 的类型,如以下示例所示:You also can explicitly cast a nullable value type to a non-nullable type, as the following example shows:

int? n = null;

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

在运行时,如果可为空的值类型的值为 null,则显式强制转换将抛出 InvalidOperationExceptionAt run time, if the value of a nullable value type is null, the explicit cast throws an InvalidOperationException.

不可为 null 的值类型 T 隐式转换为相应的可为空值类型 T?A non-nullable value type T is implicitly convertible to the corresponding nullable value type T?.

提升的运算符Lifted operators

预定义的一元运算符和二元运算符或值类型 T 支持的任何重载运算符也受相应的可为空值类型 T? 支持。The predefined unary and binary operators or any overloaded operators that are supported by a value type T are also supported by the corresponding nullable value type T?. 如果一个或全部两个操作数为 null ,则这些运算符(也称为提升的运算符)将生成 null;否则,运算符使用其操作数所包含的值来计算结果。These operators, also known as lifted operators, produce null if one or both operands are null; otherwise, the operator uses the contained values of its operands to calculate the result. 例如:For example:

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

备注

对于 bool? 类型,预定义的 &| 运算符不遵循此部分中描述的规则:即使其中一个操作数为 null,运算符计算结果也可以不为 NULL。For the bool? type, the predefined & and | operators don't follow the rules described in this section: the result of an operator evaluation can be non-null even if one of the operands is null. 有关详细信息,请参阅布尔逻辑运算符一文的可以为 null 的布尔逻辑运算符部分。For more information, see the Nullable Boolean logical operators section of the Boolean logical operators article.

对于比较运算符 <><=>=,如果一个或全部两个操作数都为 null,则结果为 false;否则,将比较操作数的包含值。For the comparison operators <, >, <=, and >=, if one or both operands are null, the result is false; otherwise the contained values of operands are compared. 请勿作出如下假定:由于某个特定的比较(例如 <=)返回 false,则相反的比较 (>) 返回 trueDo not assume that because a particular comparison (for example, <=) returns false, the opposite comparison (>) returns true. 以下示例显示 10The following example shows that 10 is

  • 既不大于等于 nullneither greater than or equal to null
  • 也不小于 nullnor less than 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

以上示例还表明,对两个均为 null 的可为空的值类型实例进行相等比较,其计算结果为 trueThe preceding example also shows that an equality comparison of two nullable value type instances that are both null evaluates to true.

如果在两个值类型之间存在用户定义的转换,则还可在相应的可为空值类型之间使用同一转换。If there exists a user-defined conversion between two value types, the same conversion can also be used between the corresponding nullable value types.

装箱和取消装箱Boxing and unboxing

可为空值类型的实例 T?已装箱,如下所示:An instance of a nullable value type T? is boxed as follows:

  • 如果 HasValue 返回 false,则生成空引用。If HasValue returns false, the null reference is produced.
  • 如果 HasValue 返回 true,则基础值类型 T 的对应值将装箱,而不对 Nullable<T> 的实例进行装箱。If HasValue returns true, the corresponding value of the underlying value type T is boxed, not the instance of Nullable<T>.

可将值类型 T 的已装箱值取消装箱到相应的可为空值类型 T?,如以下示例所示:You can unbox a boxed value of a value type T to the corresponding nullable value type T?, as the following example shows:

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

如何确定可为空的值类型How to identify a nullable value type

下面的示例演示了如何确定 System.Type 实例是否表示已构造的可为空值类型,即,具有指定类型参数 TSystem.Nullable<T> 类型:The following example shows how to determine whether a System.Type instance represents a constructed nullable value type, that is, the System.Nullable<T> type with a specified type parameter T:

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

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

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

如示例所示,使用 typeof 运算符来创建 System.Type 实例。As the example shows, you use the typeof operator to create a System.Type instance.

如果要确定实例是否是可为空的值类型,请不要使用 Object.GetType 方法获取要通过前面的代码测试的 Type 实例。If you want to determine whether an instance is of a nullable value type, don't use the Object.GetType method to get a Type instance to be tested with the preceding code. 如果对值类型可为空的实例调用 Object.GetType 方法,该实例将装箱ObjectWhen you call the Object.GetType method on an instance of a nullable value type, the instance is boxed to Object. 由于对可为空的值类型的非 NULL 实例的装箱等同于对基础类型的值的装箱,因此 GetType 会返回表示可为空的值类型的基础类型的 Type 实例:As boxing of a non-null instance of a nullable value type is equivalent to boxing of a value of the underlying type, GetType returns a Type instance that represents the underlying type of a nullable value type:

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

另外,请勿使用 is 运算符来确定实例是否是可为空的值类型。Also, don't use the is operator to determine whether an instance is of a nullable value type. 如以下示例所示,无法使用 is 运算符区分可为空值类型实例的类型与其基础类型实例:As the following example shows, you cannot distinguish types of a nullable value type instance and its underlying type instance with the is operator:

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?

可使用以下示例中提供的代码来确定实例是否是可为空的值类型:You can use the code presented in the following example to determine whether an instance is of a nullable value type:

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;
}

备注

此部分中所述的方法不适用于可为空的引用类型的情况。The methods described in this section are not applicable in the case of nullable reference types.

C# 语言规范C# language specification

有关更多信息,请参阅 C# 语言规范的以下部分:For more information, see the following sections of the C# language specification:

请参阅See also