可空类型

本文深入探讨了C#中的可空类型概念及其应用。详细介绍了如何使用?类型修饰符创建可空形式的值类型,以及可空类型的基础类型、HasValue属性和Value属性的作用。此外,还解释了可空转换、提升转换和提升运算符的工作原理。

在与数据库交互时支持所有类型包括值类型的可空值是很重要的而一直以来通用编程语言很少或没有提供这方面的支持。在没有直接语言支持的情况下,虽然也存在许多用于处理空值和值类型的方法,但都存在缺点。例如,一种方法是使用“特殊”值(例如将 −1 用于整数)指示空值,但是这种方法只有在能够确定未使用的值的情况下有效。另一种方法是在单独的字段或变量中维护布尔空值指示符,但是这种方法不是很适合参数和返回值。第三种方法是使用一组用户定义的可空类型,但是这仅适用于属于闭集的类型集合。C# 的可空类型 (nullable type) 通过为所有值类型的可空形式提供完整和集成的支持,解决了这个由来已久的问题。

可空类型是使用 ? 类型修饰符来构造的。例如int? 是预定义类型 int 的可空形式。可空类型的基础类型必须是非可空的值类型。

可空类型是一个组合了基础类型的值和布尔空值指示符的结构。可空类型的实例具有两个公共只读属性:bool 类型的 HasValue 和可空类型的基础类型的 ValueHasValue 对所有非空实例都为 true,对空实例为 false。当 HasValue true 时,Value 属性返回所包含的值。当 HasValue false 时,尝试访问 Value 属性将引发异常。

可从任何非可空值类型隐式转换到该类型的可空形式。此外,还可从 null 文本隐式转换到任何可空类型。在下面的示例中

int? x = 123;
int? y = null;

if (x.HasValue) Console.WriteLine(x.Value);
if (y.HasValue) Console.WriteLine(y.Value);

int 123 null 文本被隐式转换为可空类型 int?。该示例针对 x 输出 123但是第二个 Console.WriteLine 未执行因为 y.HasValue false

可空转换 (Nullable conversion) 和提升转换 (lifted conversion) 允许对非可空值类型进行操作的预定义转换和用户定义转换也能够用于这些类型的可空形式。同样提升运算符 (lifted operator) 允许用于非可空值类型的预定义运算符和用户定义运算符也能够用于这些类型的可空形式。

对于从非可空值类型 S 到非可空值类型 T 的每个预定义转换将自动存在从 S? T? 的预定义可空转换。这种可空转换是基础转换的一种空传播 (null propagating) 形式:它将空的源值直接转换为空的目标值,但是对其他值则执行基础非空转换。此外还进一步提供了从 S T? 和从 S? T 的可空转换,后一种转换作为在源值为空时将引发异常的显式转换。

下面是一些可空转换示例。

int i = 123;
int? x = i;           // int --> int?
double? y = x;        // int? --> double?
int? z = (int?)y;     // double? --> int?
int j = (int)z;       // int? --> int

当源和目标类型均为非可空值类型时用户定义的转换运算符将具有提升形式。源和目标类型将添加一个 ? 修饰符以创建提升形式。与预定义的可空转换类似,提升转换运算符也可传播空值。

当操作数类型和结果类型全都为非可空值类型时非比较运算符具有提升形式。对于非比较运算符,每个操作数类型和结果类型将添加一个 ? 修饰符以创建提升形式。例如,接受两个 int 操作数并返回一个 int 的预定义 + 运算符的提升形式是接受两个 int? 操作数并返回一个 int? 的运算符。与提升转换类似,提升非比较运算符也进行空传播:如果提升运算符的任一操作数为空,则结果为空值。

下面的示例使用 + 提升运算符将两个 int? 值相加

int? x = GetNullableInt();
int? y = GetNullableInt();
int? z = x + y;

z 的赋值实际上等价于

int? z = x.HasValue && y.HasValue ? x.Value + y.Value : (int?)null;

由于存在从非可空值类型到其可空形式的隐式转换当只有一个操作数是可空类型时提升运算符同样适用。下面的示例使用与上述示例相同的提升后的 + 运算符:

int? x = GetNullableInt();
int? y = x + 1;

如果 x 为空 y 被赋值为空。否则y 被赋以 x 加一的值。

C# 的可空转换、提升转换和提升非比较运算符的空传播语义非常类似于 SQL 中的对应转换和运算符。但是,C# 的提升比较运算符产生标准的布尔结果而不是引入 SQL 的三值布尔逻辑。

当操作数类型均为非可空值类型并且结果类型为 bool 比较运算符==!=<><=>=具有提升形式。比较运算符的提升形式是通过向每个操作数类型添加一个 ? 修饰符(但是不添加到结果类型)构成的。== != 运算符的提升形式将两个空值视为相等,并且空值不等于非空值。如果一个为空或者两个操作数都为空,<><= >= 运算符的提升形式返回 false

== != 运算符的操作数之一为 null 文本时另一个操作数可以是任何可空类型而不管基础值类型是否实际声明了该运算符。在没有为运算符 == != 提供实现的情况下,操作数的 HasValue 属性的检查将被替换。此规则的效果在于,类似如下的语句

if (x == null) Console.WriteLine("x is null");

if (x != null) Console.WriteLine("x is non-null");

对于任何可空类型或引用类型的 x 都是允许的从而为可为空值的所有类型执行空值检查提供一种公共的方法。

另外还提供了空合并运算符 (null coalescing operator) ??。如果 a 为非空 a ?? b 的结果为 a否则结果为 b。从效果看b 提供了要在 a 为空时使用的值。

a 为可空类型而 b 为非可空类型时只要操作数类型之间存在适当的隐式转换a ?? b 将返回非可空值。在下面的示例中

int? x = GetNullableInt();
int? y = GetNullableInt();
int? z = x ?? y;
int i = z ?? -1;

x ?? y 的类型为 int?但是 z ?? -1 的类型为 int。后一种运算特别方便,因为它从类型移除 ?,同时还提供要在为空值时使用的默认值。

空合并运算符也适用于引用类型。下面的示例

string s = GetStringValue();
Console.WriteLine(s ?? "Unspecified");

输出 s 的值或在 s 为空值时输出 Unspecified


转载于:https://www.cnblogs.com/gfsoft/archive/2006/07/31/463863.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值