原文出处: 农码一生 值类型为什么不可以为空首先我们都知道引用类型默认值都是null,而值类型的默认值都有非null。 为什么引用类型可以为空?因为引用类型变量都是保存一个对象的地址引用(就像一个url对应一个页面),而引用类型值为null的时候是变量值指向了一个空引用(如同一个空的url) 那为什么值不能有空值呢?其实很简单,因为如int值范围是-2147483648到2147483647。其中根本就没有给null值留那么一个位置。 我们为什么需要用到可空类型举个栗子吧,我们定义一个人(Person),它有三个属性出生日期(BeginTime)、死亡日期(EndTime)、年龄(Age)。 如果这个人还健在人世,请问怎么给死亡日期赋值?有人很聪明说“为空啊”。是的,这就是我们的需求。 微软在C#2.0的时候就为我们引入了可null值类型( System.Nullable ),那么下面来定义Person类。 C#
这样,我们就可以很容易获得一个人的年龄了。 C#
可空类型的实现我们前面用到了 System.Nullable 来表示可空时间类型,其实平时我们用得更多的是 DateTime? 直接在类型T后面加一个问号,这两种是等效的。多亏了微软的语法糖。 我们来看看 System.Nullable 到底是何物。 搜噶,原来是一个结构。还看到了我们属性的 HasValue和Value属性。原来竟这般简单。一个结构两个属性,一个存值,一个存是否有值。那么下面我们也来试试吧。 不好意思,让大家失望了。前面我们就说过了,值类型是不可以赋值null的(结构也是值类型)。 怎么办!怎么办!不对啊,微软自己也是定义的结构,它怎么可以直接赋值null呢。(奇怪,奇怪,毕竟是人家微软自己搞得,可能得到了特殊的待遇吧) 可是,这样就让我们止步了吗?NO!我们都知道,看微软的IL(中间语言)的时候,就像脱了它的衣服一样,很多时候不明白的地方都可以看个究竟,下面我们就去脱衣服。 首先,我们用几种不同的方式给可空类型赋值。 C#
然后用reflector看编译后的IL。 原来如此,可空类型的赋值直接等效于构造实例。赋null时其实就是调用空构造函数,有值时就就把值传入带参数的构造函数。(柳暗花明又一村。如此,我们是否可以接着上面截图中的 MyNullable 继续模拟可空类型呢?且继续往下看。) C#
哟西,基本上已经模拟出了可空类型出来的。(但是我们还是不能直接赋值,只能通过构造函数的方式来使用自定义的可空类型)。 全部代码如下: C#
和系统的可空类型得出了相同的结果。 总结
============== 2016-06-05更新============== 上面我们提出了疑问“怎么样才可以做到直接赋值呢”,本来我是没有好的解决办法。这里要感谢我们的园友@冲杀给我提供了好的解决方案。 implicit(关键字用于声明隐式的用户定义类型转换运算符。) C#
只需要在 struct MyNullable 中添加以上代码,就可以直接赋值了。(作用等效于是直接重写了“=”赋值符号) 完整代码如下: C#
如此,我们已经完成了自定义可空类型的直接赋值。但只是部分,如果想要赋值null呢? 同样还是出现了最开始的编译错误。我们想到既然上面的值赋值可以重新(隐式转换),那null应该也可以啊(null是引用类型的一个特定值)。 再加一个重载: C#
如此可以满足我们的需求了(并无异常)。 可惜美中不足,如果给 p2.EndTiem 赋值一个非空字符串时,要运行时才会报错(而系统的可空类型会在编译期就报错)。不知道大神们可有解!! 虽然如此,能做到直接赋值还是让我小小激动了一把。为此,特意查了下关键字 implicit operator ,又是让我小小激动了一把,我们不仅可以“重写”赋值,我们还可以“重写”+ – * / % & | ^ > == != > = 下面我们先来“重写”下自定义可空类型的比较(==)运算符。 C#
C#
结果完全符合! 完整代码如下: C#
转换关键字:operator、explicit与implicit解析资料:http://www.cnblogs.com/hunts/archive/2007/01/17/operator_explicit_implicit.html 大家还可以玩出更多的花样!!! 加入伯乐在线专栏作者。扩大知名度,还能得赞赏!详见《招募专栏作者》
|
|