文章目录
前言
可空类型(Nullable)是一个极具实用性的特性,它为我们处理那些可能出现未赋值情况的数据提供了便捷且合理的方式。而其中,单问号(?)和双问号(??)这两个符号在可空类型的运用中扮演着关键角色,各自有着独特且重要的功能。
一、单问号(?)
在 C# 中,像 int、double、bool 等这些基础的数据类型,按照常规情况是无法直接赋值为 null 的。然而,实际编程场景中,尤其是在处理诸如数据库等外部数据源时,常常会遇到数值类型或者布尔型的元素可能未被赋值的情况。这时,单问号(?)就派上用场了,它用于将这些原本不能赋值为 null 的数据类型转变为可空类型(Nullable 类型),意味着这个数据类型被赋予了可以存储 null 值的能力。
例如,以下两种写法是等价的:
csharp
int? i = 3;
Nullable<int> i = new Nullable<int>(3);
通过使用单问号(?),我们定义了一个可空的整型变量 i,它既可以像普通整型变量那样存储 int 类型正常范围内的值(例如 3),也可以存储 null 值。对比普通的整型变量声明:
csharp
int i; // 默认值 0
int? ii; // 默认值 null
可以清晰地看到,普通整型变量在未初始化赋值时,会有一个默认的初始值 0,而可空整型变量 ii 的默认值则是 null,这体现了可空类型在表示未赋值情况方面的独特优势。
以 Nullable 为例,它读作 "可空的 Int32",其取值范围非常灵活,不仅可以被赋值为 -2,147,483,648 到 2,147,483,647 之间的任意值(这是 Int32 类型本身正常的取值范围),还可以被赋值为 null 值。类似地,对于 Nullable 变量而言,它打破了常规布尔型只能取 true 或 false 的限制,额外增加了可以赋值为 null 的能力,这在很多场景下都非常有用。
比如在处理数据库相关操作时,数据库中的布尔型字段可能会出现三种状态:存储值 true、存储值 false,或者该字段未定义(也就是对应程序中的 null 值)。可空类型就能完美地适配这种情况,让我们在程序中可以准确地映射和处理数据库中的数据状态,避免因数据可能未赋值而引发的错误或不合理的默认赋值情况。
声明一个可空类型(Nullable)有着特定的语法规范,其形式如下:
csharp
<data_type>? <variable_name> = null;
以下是一个展示可空数据类型用法的实例:
csharp
using System;
namespace CalculatorApplication
{
class NullablesAtShow
{
static void Main(string[] args)
{
// 声明不同的可空类型变量,并进行不同的赋值操作
int? num1 = null;
int? num2 = 45;
double? num3 = new double?();
double? num4 = 3.14157;
bool? boolval = new bool?();
// 显示值
Console.WriteLine("显示可空类型的值: {0}, {1}, {2}, {3}",
num1, num2, num3, num4);
Console.WriteLine("一个可空的布尔值: {0}", boolval);
Console.ReadLine();
}
}
}
当上述代码被编译和执行时,会输出如下结果:
plaintext
显示可空类型的值:, 45, , 3.14157
一个可空的布尔值:
这里可以看到,对于赋值为 null 的可空变量(如 num1 和 num3),在输出时会显示相应的空白占位(具体输出格式可能因不同环境稍有差异,但能体现出其值为 null 的特点),而赋了具体值的可空变量(如 num2 和 num4)则正常输出对应的值,可空布尔型变量 boolval 由于初始化为 null,输出时也相应地体现出未赋值的状态。
二、双问号(??)
双问号(??)被称为 Null 合并运算符,它主要用于定义可空类型和引用类型的默认值,为类型转换设定了一个预设值,以防可空类型的值为 null。
Null 合并运算符的特性:如果第一个操作数的值为 null,那么运算符就返回第二个操作数的值;反之,如果第一个操作数不为 null,则返回第一个操作数的值。它还能够把操作数类型隐式转换为另一个可空(或不可空)的值类型的操作数的类型,确保整个运算在类型匹配方面的合理性。
以下是一个演示 Null 合并运算符用法的实例:
csharp
using System;
namespace CalculatorApplication
{
class NullablesAtShow
{
static void Main(string[] args)
{
double? num1 = null;
double? num2 = 3.14157;
double num3;
// 使用 Null 合并运算符进行赋值判断
num3 = num1?? 5.34; // 因为 num1 此时为 null 值,所以返回 5.34
Console.WriteLine("num3 的值: {0}", num3);
num3 = num2?? 5.34;
Console.WriteLine("num3 的值: {0}", num3);
Console.ReadLine();
}
}
}
当这段代码被编译和执行后,会产生如下结果:
plaintext
num3 的值: 5.34
num3 的值: 3.14157
在上述代码中,第一次对 num3 赋值时,由于 num1 的值为 null,根据 Null 合并运算符(??)的规则,就会返回第二个操作数 5.34 作为 num3 的值;而第二次赋值时,num2 的值不为 null(其值为 3.14157),所以直接返回 num2 的值给 num3。
这种机制在实际编程中有诸多应用场景,比如在从配置文件或者用户输入获取数据时,数据有可能是缺失(对应 null 值)的情况。我们可以利用 Null 合并运算符为这些可能为 null 的可空类型变量设置一个合理的默认值,确保后续程序在使用这些数据时能够有一个明确的、符合预期的值可用,避免因 null 值引发的诸如空指针异常等各种错误。