随着C#语言最新标准的出炉,现在它也提供了对可空类型的支持。这个小变化将会在处理那些包括可选项的数据库记录时非常有用。当然在其他地方,它也是非常有用的。
简单说来,可空数据类型就是包含了所定义的数据类型或者值的空(null)的类型。C#的ECMA-334标准提供了对所有C#值类型的可空版本的描述。
定义可空类型 定义可空类型和非可空类型基本类似,不同的是采用了?来表示。如定义一个整型,你可以使用简单的语句:
为了使得myInt能够存储一个空值,你可以这样声明它:
你可以看到,这两个变量看上去好像是一样的。但是,可空类型的版本是非常不同的。可空的版本事实上是一个结构,它将值类型和一个标记该值是否为空的标志位结合在一起。一个可空类型有两个公共可读的属性,HasValue和value。如果存储了一个值那么HasValue这个布尔型变量就为true。否则,如果变量是空值就是false。如果HasValue是true,你可以获取这个变量的值。如下有两个对可空变量的有效赋值:
double? myDouble = 3.1415926; double? myOtherDouble = null; |
你可以看到,myDouble被赋值了,但是也可以被赋为空。在第二个语句里,myOtherDouble被初始化一个空值,这在一个非可空类型里不能这样做的。
使用可空类型 可空类型可以像普通值类型一样的使用。事实上,可以使用内建的隐式转换来转换相同类型的可空变量和非可空变量。这意味着你可以在一个标准整型和可空整型之间相互转换:
int? nFirst = null; int Second = 2;
nFirst = Second; // 有效 nFirst = 123; // 有效 Second = nFirst; // 同样有效
nFirst = null; // 有效 Second = nFirst; // 例外,后者是非空类型 |
在以上的语句里,你可以看到如果可空变量不包含空值的话是可以和非可空变量交换值的。如果它是一个空值,那么就会抛出例外。为了防止例外,你可以使用可空变量的HasValue属性:
if (nFirst.HasValue) Second = nFirst; |
你可以看到,如果nFirst有值赋值就会发生,否则程序会跳过此句语句。
使用可空类型的操作符 虽然可以使用相同值类型的可空和非可空变量的转换,也必须对操作符进行一些改变使得它们可以处理可空和非可空值。这些操作符被称为提升的操作符。
考虑如下代码:
int ValA = 10; int? ValB = 3;
int? ValC = ValA * ValB; |
在ValC里存储了什么?ValC中存储了30。标准操作符被扩展使得它们能够处理可空类型。考虑到如下的变化:
int ValA = 10; int? ValB = null;
int? ValC = ValA * ValB; |
ValC这次值为多少?ValC为空。无论哪个操作数为空,提升的操作符的结果为空。即使进行加法或减法,结果也为空。
如果ValC不为可空类型呢?如下的代码会有什么样的结果?
int ValA = 10; int? ValB = null;
int ValC = ValA * ValB; // ValC 不为可空类型 |
代码将会抛出一个异常。ValA*ValB结果为空,但是不能赋值为非可空类型,这将会导致程序异常的抛出。