《CLR via C#》 可空值类型
System.Nullable<T>
结构
可空值类型能表示null
主要是因为多了一个Boolean
类型的字段。其本身是值类型,仍然可存储在栈上。
1[Serializable, StructLayout(LayoutKind.Squential)]
2public struct Nullable<T> where T : struct {
3 private Boolean hasValue = false; // 假定null
4 internal T value = default(T); // 假定所有位都为零
5 // 其他很多方法...
6}
使用可空值类型
C#用问号表示法来声明可控值类型
1int? x = 5;
2int? y = null;
3// 等价于
4Nullable<int> x = 5;
5Nullable<int> y = null;
对于可空值类型的转换和转型
1// 从int隐式转换为Nullable<int>
2int? a = 5;
3
4// 从'null'隐式转换为Nullable<int>
5int? b = null;
6
7// 从Nullable<int>显式转换为int
8int c = (int) a;
9
10// 从int转型为Nullable<double>
11double? d = 5;
12
13// 从Nullable<int>转型为Nullable<double>
14double? e = b;
可空值类型操作符
- 一元操作符(+,++,-,–,!,~):操作数是null,结果就为null,剩下于非空值类型一样。
- 二元操作符(+,-,*,/,%,&,|,^,«,»):操作数是null,结果就为null,剩下于非空值类型一样。有一个例外,在&于|操作符应用于Boolean?的时候。
行:操作数1
列:操作数2true false null true &=true
|=true&=false
|=true&=null
|=truefalse &=false
|=true&=false
|=false&=false
|=nullnull &=null
|=true&=false
|=null&=null
|=null - 相等性操作符(==,!=):两个操作数都是
null
,两者相等。一个操作数是null
,两者不相等。两个操作数都不是null
,就比较值。 - 关系操作符(<,>,<=,=>):两个操作数任何一个是
null
,结果就是false
。两个操作数都不是null
,就比较值。
提示
可定义自己的值类型来重载上述各种操作符
1public struct Point {
2 private int x, y;
3 public Point(int x, int y) {
4 this->x = x;
5 this->y = y;
6 }
7 public static bool operator==(Point p1, Point p2) {
8 return (p1.x == p2.x) && (p1.y == p2.y);
9 }
10}
11
12Point? p1 = new Point(1, 1);
13Point? p2 = new Point(2, 2);
14// 调用重载的操作符方法
15Console.WriteLine("Equal? " + (p1 == p2).ToString());
空接合操作符
即??
操作符,它获取两个操作数,假如左边的操作数不为null
,就返回这个操作数的值。否则返回右边的值。
1int? b = null;
2// 下面等价于
3// int x = (b.HasValue) ? b.Value : 123;
4int x = b ?? 123;
与?:操作符的区别
表达式支持比?:
操作符更好,复合情形中更清晰
1// 表达式支持
2Func<string> f = () => SomeMethod() ?? "Untitled";
3// 而?:做不到
4Func<string> f = () => {
5 var temp = SomeMethod();
6 return temp != null ? temp : "Untitled";
7}
8
9// 复合情形中比?:更好用
10string s = SomeMethod() ?? SomeMethod2() ?? "Untitled";
CLR对可空值类型的特殊支持
- 装箱:对
Nullable<T>
的实例装箱时,检测是否为null
,如果为null
,则不会装箱任何东西,直接返回null
。否则从可空值类型中取出值并进行装箱。 - 拆箱:可拆为
T
或Nullable<T>
- 调用
GetType
:在Nullable<T>
对象上调用GetType
CLR会返回类型T
而不是Nullable<T>
。 - 调用接口方法:将
Nullable<T>
类型的变量调用接口int
类型的接口IComparable<int>
。但Nullable<T>
并没有实现这个接口,但编译器允许代码通过,并可执行。