4.7 创建一个可以被初始化为空的值类型
问题
您有一个数字类型的变量,用于控制从数据库中获取的数值。数据库可能为这个值返回一个null值。您需要一个简洁的方法来存储这个数值,甚至它返回为null。
解决方案
使用可空类型。有两个创建可空类型的方法。第一种方法是使用?类型修饰符:
int? myDBInt = null;
第二种方法是使用Nullable<T>泛型类型:
Nullable<int> myDBInt = new Nullable<int>();
讨论
本质上,下面两个声明是等价的:
int? myDBInt = null;
Nullable<int> myDBInt = new Nullable<int>();
两个声明中,myDBInt都被认为是可空类型并初始化为null。一个可空类型实现了InullableValue接口,它只有两个属性成员:HasValue和Value。如果把可空类型设置为null,HasValue属性将返回false,否则将返回true。如果HasValue返回true,就可以访问Value属性以获得可空数据类型里当前存放的值。如果引发了InvalidOperationException异常,这是因为此时Value属性还未被定义。
另外,测试可空类型可以有两种方法。第一,使用HasValue属性如下:
if (myDBInt.HasValue)
Console.WriteLine("Has a value: " + myDBInt.Value);
else
Console.WriteLine("Does not have a value (NULL)");
第二种方法是跟null对比:
if (myDBInt != null)
Console.WriteLine("Has a value: " + myDBInt.Value);
else
Console.WriteLine("Does not have a value (NULL)");
两种方法都可以让人接受。
当需要把可空类型转换为非可空类型时,转换操作将正常进行,如果可空类型被设置为null就会引发一个InvalidOperationException异常。当把一个非可空类型转换为可空类型时,转换操作将正常运行,不会引发InvalidOperationException异常,非可空类型永远不会为null。
需要提防的是可空类型在进行比较运算的时候。例如执行下列代码时:
if (myTempDBInt < 100)
Console.WriteLine("myTempDBInt < 100");
else
Console.WriteLine("myTempDBInt >= 100");
“myTempDBInt < 100”这句代码明显有错。为了修正它,您不得不检查myTempDBInt是否为空。如果不是,才能执行if语句里的代码块:
if (myTempDBInt != null)
{
if (myTempDBInt < 100)
Console.WriteLine("myTempDBInt < 100");
else
Console.WriteLine("myTempDBInt >= 100");
}
else
{
// 在这里处理空值
}
另外一个有趣的事情是您可以象使用一般数字类型一样使用可空类型,如:
int? DBInt = 10;
int Value = 2;
int? Result = DBInt + Value; // Result == 12
如果表达式中的可空类型是一个null值,则表达式的结果为null,但如果没有可空类型的值为null,运算符会把它当成一般类型。如上例中的DBInt为null,则Result的结果也为null。