3.7 可空类型
引用类型(类)的变量可以为空,而值类型(结构)的变量不能。在一些情况下,这可能是一个问题,如把C#类型映射到数据库或XML类型。数据库或XML数量可以为空,而int或double不能为空。
处理这个冲突的一个方法是使用映射到数据库数字类型的类(这由Java实现)。使用引用类型,映射到允许空值的数据库数字,有一个重要的缺点:它带来了额外的开销。对于引用类型,需要垃圾收集器进行清理。值类型不需要用垃圾收集器清理;变量超出作用域时,从内存中删除。
C#有一个解决方案:可空类型。可空类型是可以为空的值类型。可空类型只需要在类型的后面添加“? ”(它必须是结构)。与基本结构相比,值类型唯一的开销是一个可以确定它是否为空的布尔成员。
在下面的代码片段中,x1是一个普通的int, x2是一个可以为空的int。因为x2是可以为空的int,所以可以把null分配给x2:
int x1 = 1; int? x2 = null;
因为int值可以分配给int?,所以给int?传递一个int变量总是会成功,编译器会接受它:
int? x3 = x1;
反过来是不正确的。int?不能直接分配给int。这可能失败,因此需要一个类型转换:
int x4 = (int)x3;
当然,如果x3是null,类型转换操作就会生成一个异常。更好的方法是使用可空类型的HasValue和Value属性。HasValue返回true或false,这取决于可空类型是否有值,Value返回底层的值。使用条件操作符填充x5,不会抛出异常。如果x3是null, HasValue就返回false,这里给变量x5提供-1:
int x5 = x3.HasValue ? x3.Value : -1;
使用合并操作符,可空类型可以使用较短的语法。如果x3是null,则用变量x6给它设置-1,否则提取x3的值:
int x6 = x3 ? ? -1;
注意:对于可空类型,可以使用能用于基本类型的所有可用操作符,例如,可用于int?的+、-、*、/等。每个结构类型都可以使用可空类型,而不仅是预定义的C#类型。