C#学习笔记(二十八)-- 可空类型

一、可空类型

  值类型必须包含一个值,它们可以在声明之后、赋值之前,在未赋值的状态下存在,但不能使用未赋值的变量。而引用类型可以是null。

  有时让值类型为空时很有用的(尤其是在处理数据库时),泛型使用System.Nullable<T>类型提供了使值类型为空的一种方式。例如:

System.Nullable<int> nullableInt;

  这行代码声明了一个变量nullableInt,它可以拥有int变量能包含的任意值,还可以拥有值null,所以可以编写如下的代码:

nullableInt = null;

  前面的赋值语句等价于:

nullableInt = new System.Nullable<int>();

  与其他任意变量一样,无论是初始化为null(使用上面的语法),还是通过给他赋值来初始化,都不能在初始化之前使用它。

  可以项测试引用类型一样测试可空类型,看看它们是否为null:

if(nullableInt == null)
{
   ...
}

  另外,可以使用HasValue属性:

if(nullableInt.HasValue)
{
   ...
}

  尽管引用类型存在HasValue属性,但是引用并不能使用这种方法,因为如果引用类型为null的话,就说明不存在对象,自然不能通过对象来访问这个属性,否则就会抛出一个异常。

  使用HasValue属性可以以查看可空类型的值。如果HasValue是true,就说明该可空变量并非空值。但如果返回的HasValue是false,则说明该可空变量是null,此时访问Value属性会抛出System.InvalidOperationException类型的异常。

  可空类型非常有用,以至于它们修改了C#的语法。声明一个可空类型的变量不使用上述的语法,而是使用下面的语法:

int? nullableInt;

  1)运算符和可空类型

  对于简单类型(如int),可以使用+、-等运算符来处理值。而对于对应的可空类型,这是没有区别的:包含在可空类型中的值会隐式转换为需要的类型,使用适当的运算符。这也适用于结构和自己提供的而运算符。例如:

int? op1 = 5;
int? result = op1 *2;

  注意,这里的result的类型也是int?,如果result的类型改为int,则代码不会被编译,需要进行显式转换,或是利用Value属性访问值:

int? op1 = 5;
int result = (int)op1 * 2;

int result = op1.Value * 2;

  只要op1不为空值,上述的代码就可以正常运行。如果op1是null,就会生成System.InvalidOperationException类型的异常。

  当运算表达式中的一个或两个值为null时,计算结果又该如何:

int? op1 = null;
int? op2 = 5;
int? result = op1 * op2;

  答案是:对了除了bool?以外的所有简单可空类型,该操作的结果是null,可以把它解释为“不能计算”。

  2)??运算符

  为了进一步减少处理可空类型所需的代码量,使可空变量的处理变得更见到那,可以使用??运算符。这个运算符称为空接合运算符,是一个二元运算符,允许给可能等于null的表达式提供另一个值。如果第一个操作数不是null,该运算符就等于第一个操作数,否则,该运算符就等于第二个操作数。下面的两个表达式的作用是相同的:

op1 ?? op2;
op1 == null ? op2 : op1;

  在这两行代码中,op1可以是任意可空表达式,包括也引用类型和更重要的可空类型。因此,如果可空类型是null,就可以使用??运算符提供需要使用的默认值,如下所示:

int? op1 = null;
int result = op1 * 2 ?? 5;

  在这个示例中,op1是null,所以op1*2也是null,因此??运算符将值5赋予result。这里要特别注意,在结果放入int类型的变量result不需要进行显式转换,??运算符会自动处理这个转换。还可以把??表达式的结果传入int?中:

int? result = op1 * 2 ?? 5;

  在处理可空变量时,??运算符有许多用途,它也是一种提供默认值的便捷方式,不需要使用if结构中的代码块或容易引起混淆的三元运算符。

  3)?.运算符

  这个操作符通常称为Elvis运算符或空条件运算符,有助于避免繁杂的空值检查造成的代码歧义。例如,如果像得到给定客户的订单数,就需要在设置计数值之前检查空值:

int count = 0;
if (customer.orders != null)
{
   count = customer.orders.Count();
}

  如果只是编译了这段代码,但客户没有订单(即为null),就会抛出System.ArgumentNullException:

int count = customer.orders.Count();

  使用?.运算符,会把int?count设置为null,而不会抛出一个异常:

int? count = customer.orders?.Count();

  配合??运算符,还可以给count赋一个null时的默认值:

int? count = customer.orders?.Count ?? 0;

  空条件运算符的另一个用途是触发事件,触发事件的最常见方法是使用如下代码模式:

var onChanged = Onchanged;
if (onChanged != null)
{
   onChanged(this, args);
}

  这种模式不是线程安全的,因为有人会在null检查已经完成后,退订最后一个事件处理程序。此时会抛出异常,程序崩溃。使用空条件运算符可以避免这种情形:

Onchange?.Invoke(this,args);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值