【.NET Core】可为null类型详解
文章目录
- 【.NET Core】可为null类型详解
- 一、概述
- 二、可为空的值类型
- 2.1 声明和赋值
- 2.2 检查可为空值类型
- 2.3 基础类型与可为空的值类型互换
- 2.4 可为空的值类型装箱和取消装箱
- 2.5 如何确定可为空的值类型
- 三、可为 null 的引用类型
一、概述
null
关键字是表示不引用任何对象的空引用的文字值。null
是引用类型变量的默认值。普通值类型不能为null
,可为空的值类型除外
二、可为空的值类型
可为null
值类型T?
表示其基础值类型T的所有值及额外的null值。基础值类型T
本身不能是可为空的值类型。
任何可为空的值类型都是泛型System.Nullable<T>
结构的实例。可使用以下任何一种互换形式引用具有基础类型T的可为空值类型:Nullable<T>
或T?
。
需要表示基础类型的未定义值时,通常使用可为空的值类型。如:布尔值或bool
变量只能为true
或false
。但是,在某些应用程序中,变量值可能未定义或缺失。在这种情况下可以使用bool?类型。
2.1 声明和赋值
由于值类型可隐式转换为相应的可为空的值类型,因此可以像其基础类型赋值一样,向可为空值类型的变量赋值,还可以分配null
值。具体实例如下:
double? pi=3.1415926;
char? letter='c';
int a=110;
int? ab=a;
bool? flag =null;
int?[] arr= new int?[8];
可为空值类型的默认值表示null
,也就是说,它是其Nullable<T>.HasValue
属性返回false
的实例。
2.2 检查可为空值类型
可将is运算符与类型模式结合使用,既检查null
的可为空值类型的实例,又检索基础类型的值:
int? a = 42;
if(a is int valueOfA){
Console.WriteLine($"a is {valueOfA}");
}else{
Console.WriteLine("a does not have a value.");
}
始终可以使用以下只读属性来检查和获取可为空值类型变量的值:
Nullable<T>.HasValue
指示可为空值类型的实例是否有基础类型的值。- 如果
HasValue
为true
,则Nullable<T>.Value
获取基础类型的值。如果HasValue
为false
,则Value
属性将引发IvalidOperationException
。
使用HasValue
属性在显示值之前测试变量是否包含该值:
int? b=10;
if(b.HasValue)
{
Console.WriteLine($"b is {b.Value}");
}else{
Console.WirteLine("b does not have a value.");
}
还可以通过可为空类型与null进行比较,如:
int? bc = 7;
if (bc != null)
{
Console.WriteLine($"c is {c.Value}");
}
else
{
Console.WriteLine("c does not have a value");
}
2.3 基础类型与可为空的值类型互换
如果要将可为空值类型的值分配给不可以为null
的值类型变量,则可能需要指定要分配的替代null
的值。使用Null
和并操作符??
执行此操作(也可将Nullable<T>.GetValueOrDefault(T)
方法用于相同的目的):
int? pi=3.14;
int b = pi??-1;
Console.WriteLine($"b is {b}");
int? c=null;
int d =c??-1;
Console.WriteLine($"d is {d}");
如果要使用基础值类型的默认值为null
,需要使用Nullable<T>.GetValueOrDefault()
方法。
还可以将可为空的值类型显示强制转换为不可为null
的类型。如下:
int? n = null;
int n2 = (int)n;
在运行时,如果可为空的值类型的值为 null
,则显式强制转换将抛出InvalidOperationException
。不可为null的值类型T
隐式转换为相应的可为空值类型T?
。
2.4 可为空的值类型装箱和取消装箱
可为空值类型的实例T?已装箱;
- 如果
HasValue
返回false
,则生成空引用。 - 如果
HasValue
返回true
,则基础值类型T的对应值将将装箱,而不对Nullable<T>
的实例进行装箱。
可将值类型T
的已装箱值取消装箱到相应的可为空值类型T?
,如示例:
2.5 如何确定可为空的值类型
如果要确定实例是否是可为空的值类型,请不要使用Object.GetType
方法获取要通过前面的代码测试的Type
实例。如果对值类型可为空的实例调用Object.GetType
方法,该实例将装箱到Object。由于对可为空的值类型的非NULL实例的装箱等同于对基础类型的值的装箱,因此GetType
会返回表示可为空的值类型的基础类型的Type
实例。
另外,请勿使用is
运算符来确定实例是否是可为空的值类型。因为无法使用is
运算符区分可为空值类型实例的类型与其基础类型实例。
综合来说,如果要判断可为空值类型,需要使用Nullable.GetUnderlyingType
和typeof
运算符。以检查实例是否具有可为空的值类型。
三、可为 null 的引用类型
由于可为null的感知上下文选择加入代码,可以使用可为null的引用类型。可为null的引用类型,null静态分析警告和null包容运算符是可选的语言功能。
在可为null的感知上下文中:
- 引用类型T的变量必须用非null值进行初始化,并且不能为其分配可能为null的值。
- 引用类型T?的变量可以用null进行初始化,也可以分配null,但是在取消引用之前必须对null进行验证检测。
- 类型为T?的变量m在应用null包含运算符时被认为是非空的。
不可为null的引用类型T和可为null的引用类型T?之间的区别按照编译器对上述规则的解释强制执行的,类型为T的变量和类型为T?的变量由相同的.NET类型表示。
string notNull = "Hello";
string? nullable = default;
notNull = nullable!;
Console.WriteLine(notNull);
变量notNull和nullable都由String
类型表示。因为不可为null
的类型和可为null的类型都存储为相同的类型,所以有几个位置不允许使用可为null的引用类型。
下面几种情况不能使用可为nulll类型:
- 可为 null 的引用类型不能用作基类或实现的接口
- 可为 null 的引用类型不能用于任何对象创建或类型测试表达式
- 可为 null 的引用类型不能是成员访问表达式的类型
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");
}