C# 引入Nullable类型,允许我们将值类型赋值为null。
其实质上是在Framework中增加了一个Nullable<T>的泛型结构类型。
看看上面的声明,我们可以确定,Nullable是一个值类型,而且限制类型参数为值类型。
另外C#在语法层面作了简化,见下面的代码。
看看反编译的结果。
实际上,编译器会将缩写方式处理成完整的结构体创建代码。
Nullable包含两个有用的属性,HasValue用来判断类型是否为空,如果不为空则可以通过Value属性获取其基础类型的值。
当其值不为空时,可以直接使用其基础类型的运算符进行操作。GetValueOrDefault 方法可以获取值或者基础类型的缺省值。
不过看看这段代码的反编译结果,你可能会发现一些问题。
原本简单的代码变得很复杂,编译器创建了新的Nullable对象,而且通过判断,如发现Nullable对象为空,则放弃加法操作,直接返回空。
继续看反编译的IL代码,还出现了box指令,因此Nullable类型的代价是很高的,如非必须,不要使用。
最后提一下 ?? 这个操作符。
The ?? defines a default value that is returned when a nullable type is assigned to a non-nullable type.
其实质上是在Framework中增加了一个Nullable<T>的泛型结构类型。
[SerializableAttribute()] public struct Nullable<T> : IFormattable, IComparable, INullableValue where T : ValueType
看看上面的声明,我们可以确定,Nullable是一个值类型,而且限制类型参数为值类型。
另外C#在语法层面作了简化,见下面的代码。
int? x = 3; Nullable<int> y = new Nullable<int>(3);
看看反编译的结果。
Nullable<int> nullable1 = new Nullable<int>(3); Nullable<int> nullable2 = new Nullable<int>(3);
实际上,编译器会将缩写方式处理成完整的结构体创建代码。
Nullable包含两个有用的属性,HasValue用来判断类型是否为空,如果不为空则可以通过Value属性获取其基础类型的值。
当其值不为空时,可以直接使用其基础类型的运算符进行操作。GetValueOrDefault 方法可以获取值或者基础类型的缺省值。
int? x = 3; int y = 1; Console.WriteLine(x + y);
不过看看这段代码的反编译结果,你可能会发现一些问题。
Nullable<int> nullable1 = new Nullable<int>(3); int num1 = 1; Nullable<int> nullable2 = nullable1; int num2 = num1; Console.WriteLine( nullable2.get_HasValue() ? new Nullable<int>(nullable2.GetValueOrDefault() + num2) : new Nullable<int>());
原本简单的代码变得很复杂,编译器创建了新的Nullable对象,而且通过判断,如发现Nullable对象为空,则放弃加法操作,直接返回空。
继续看反编译的IL代码,还出现了box指令,因此Nullable类型的代价是很高的,如非必须,不要使用。
.entrypoint // Code Size: 63 byte(s) .maxstack 3 .locals init ( [mscorlib]System.Nullable`1<int32> nullable1, int32 num1, [mscorlib]System.Nullable`1<int32> nullable2, int32 num2, [mscorlib]System.Nullable`1<int32> nullable3) L_0000: nop L_0001: ldloca.s nullable1 L_0003: ldc.i4.3 L_0004: call instance void [mscorlib]System.Nullable`1<int32>::.ctor(!0) L_0009: nop L_000a: ldc.i4.1 L_000b: stloc.1 L_000c: ldloc.0 L_000d: stloc.2 L_000e: ldloc.1 L_000f: stloc.3 L_0010: ldloca.s nullable2 L_0012: call instance bool [mscorlib]System.Nullable`1<int32>::get_HasValue() L_0017: brtrue.s L_0025 L_0019: ldloca.s nullable3 L_001b: initobj [mscorlib]System.Nullable`1<int32> L_0021: ldloc.s nullable3 L_0023: br.s L_0033 L_0025: ldloca.s nullable2 L_0027: call instance !0 [mscorlib]System.Nullable`1<int32>::GetValueOrDefault() L_002c: ldloc.3 L_002d: add L_002e: newobj instance void [mscorlib]System.Nullable`1<int32>::.ctor(!0) L_0033: box [mscorlib]System.Nullable`1<int32> L_0038: call void [mscorlib]System.Console::WriteLine(object) L_003d: nop L_003e: ret
最后提一下 ?? 这个操作符。
The ?? defines a default value that is returned when a nullable type is assigned to a non-nullable type.
// ?? operator example. int? x = null; int y = x ?? -1; // Assigns y to -1 if x is null.