C# 中的问号(?)与双问号(??)运算符详解

📅 2026/8/2 19:28:30 👁️ 阅读次数 📝 编程学习
C# 中的问号(?)与双问号(??)运算符详解

@[TOC](C# 中的问号(?)与双问号(??)运算符详解)

1. 问号(?):可空类型声明

在 C# 中,问号(?)用于声明可空类型(Nullable Types),表示该变量可以存储null值。

1.1 基本语法

int?a=newint?();Console.WriteLine(a);// 输出:null

1.2 等价写法

上述声明等价于:

int?a=null;

也等价于:

int?a;// 声明可空整型变量,默认值为 null

1.3 使用场景

可空类型主要用于值类型(如intfloatdouble等),允许它们像引用类型一样接受null值。这在数据库操作、API 响应处理等场景中非常有用。

2. 双问号(??):空值合并运算符

双问号(??)是 C# 中的空值合并运算符(Null-coalescing operator),用于简化null值检查。

2.1 基本语法

c=a??b;

2.2 等价写法

上述表达式等价于:

c=(a==null)?b:a;

2.3 使用规则与注意事项

规则 1:类型一致性要求

ab必须是相同类型,且a必须是可以为null的类型:

  • 引用类型(如objectstring等)
  • 可空值类型(如int?float?double?等)
  • dynamic动态类型

正确示例 1:引用类型

// 例1:a,b 同为引用类型,a 可以为空objecta=null;objectb=10;objectc=a??b;// a,b,c 的类型相同

正确示例 2:可空值类型

// 例2:a,b 同类型,a 为可空类型int?a=null;intb=10;intc=a??b;// 或者进行隐式转换floatc=a??b;// a??b 表达式的值为 int 型,隐式转换为 float 型

错误示例:类型不匹配

// 例3:a,b 是不同类型,编译报错int?a=null;stringb="hello";stringc=a??b;// 错误:运算符"??"无法应用于"int?"和"string"类型的操作数
规则 2:表达式类型与赋值兼容性

a ?? b表达式的值类型与ab相同,因此:

  • c必须与ab同类型,或者
  • a ?? b表达式的值进行隐式转换或强制类型转换

正确示例:类型转换

// 示例 1:转换为字符串int?a=null;intb=10;stringc=(a??b).ToString();// 示例 2:强制类型转换objecta=null;objectb=10;intc=(int)(a??b);

2.4 链式使用

双问号运算符支持链式调用,这在处理多层可能为null的值时非常方便:

stringresult=value1??value2??value3??"默认值";

3. 实际应用场景

3.1 数据库字段处理

int?ageFromDb=GetAgeFromDatabase();// 可能返回 nullintage=ageFromDb??0;// 如果为 null,则使用默认值 0

3.2 配置项读取

stringconnectionString=ConfigurationManager.AppSettings["ConnectionString"]??"DefaultConnectionString";

3.3 方法参数默认值

publicvoidProcessData(stringdata,string?fallback=null){stringactualData=data??fallback??"默认数据";// 处理 actualData}

4. 总结

运算符名称用途示例
?可空类型修饰符声明值类型变量可以存储nullint? age = null;
??空值合并运算符提供null时的默认值string name = input ?? "匿名";

关键要点:

  1. 问号(?):让值类型具备存储null的能力
  2. 双问号(??):简化null检查,提供优雅的默认值处理
  3. 类型安全:使用??时需确保操作数类型兼容
  4. 链式调用??支持多级空值检查,代码更简洁

掌握这两个运算符能显著提升 C# 代码的健壮性和可读性,特别是在处理可能缺失的数据时。