Nullable 解析
时间:2010-09-23 来源:兴说:
今天跟个朋友讨论了下Nullable。
在此列入笔记稍作记录。
在.net 3.0之后便引入了 值类型?的写法,例如 int?,float?等,其表示为可为空的值类型。
对于任何一个值类型的可空类型,其实现都是来自于 Nullable<T> 这个泛型的实现,而Nullable事实上是一个Struct。
所以有时有人会有疑问,如果int?只是一个Struct的实现。那为什么以下代码能够编译通过:
Int? i = null;
因为对于Struct,它是一个值类型,是不能为它赋予null值的。
这是需要解析的第一点,比如我们上面的那句。
事实上,编译器在编译的时候,并不会把null赋予这个值类型。
它只是在调用了Nullable的一个默认初始化函数。我们可以从编译后的IL中看出。
而对于下面这样的代码:
Int? i = 5;
编译器做的也是像上面一样的事情,在这里他是调用了相应泛型T的构造函数,初始化了一个Nullable<T>的实例出来。
然后再根据IL来观察对一个可空值类型的重复赋值:
Int? i = 0;
int? n = null;
i = 2;
n = 3;
以上代码在编译时的表现是,每一次进行赋值,它都会初始化一个新的Nullable<int>的新实例出来。
嗯,现在从IL中我们已经可以看出,每次对可空类型的赋值,无论是赋初值还是重复赋值,
事实上都是实例化出了一个Nullable<T>泛型的结构体。
然后还是回到最初的那个问题,既然可空值类型是一个Struct,那它怎么可以跟null进行比较呢?
先看IL,
从上面的IL来看,以上的语法全都是语法糖,为了方便开发人员写代码而制造出来的。因为当你书写以下的代码时:
Int? i = 0;
bool result = i == null;
比较调用的的并不是值类型的Equal,或者是引用类型的RefrenceEqual,
而是调用了Nullable的get_HasValue方法,Nullable封装了该方法以检查该值是否已存在。
所以事实上这些都是编译器的魔法,他让开发人员书写少了很多繁琐的代码,但如果我们不深入去探讨,就会陷入一些迷惑,甚至忘记了代码的本质。