《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
    列:操作数2
    true false null
    true &=true
    |=true
    &=false
    |=true
    &=null
    |=true
    false &=false
    |=true
    &=false
    |=false
    &=false
    |=null
    null &=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。否则从可空值类型中取出值并进行装箱。
  • 拆箱:可拆为TNullable<T>
  • 调用GetType:在Nullable<T>对象上调用GetTypeCLR会返回类型T而不是Nullable<T>
  • 调用接口方法:将Nullable<T>类型的变量调用接口int类型的接口IComparable<int>。但Nullable<T>并没有实现这个接口,但编译器允许代码通过,并可执行。