Nullable 解析

今天跟个朋友讨论了下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,

    而是调用了Nullableget_HasValue方法,Nullable封装了该方法以检查该值是否已存在。

     

    所以事实上这些都是编译器的魔法,他让开发人员书写少了很多繁琐的代码,但如果我们不深入去探讨,就会陷入一些迷惑,甚至忘记了代码的本质。

 

 

 

posted on 2010-09-23 01:08  兴说:  阅读(545)  评论(0编辑  收藏  举报