??
如果左侧操作数为 null,则返回右侧操作数;否则返回左侧操作数。常用于为变量设置默认值。
int? a = null;
int b = a ?? -1;
Console.WriteLine(b); // 输出: -1
??=
当左侧变量为 null 时,将其赋值为右侧的值。
int? a = null;
a ??= -1;
Console.WriteLine(a); // 输出: -1
?. (Null-Conditional Oeprator)
若左侧对象为 null,则跳过后续操作并返回 null;否则执行操作并返回结果。
using System;
public class Program {
public static void Main() {
string i = null;
int? length = i?.Length;
Console.WriteLine(length ?? -1); // 输出: -1
}
}
?[] (Null-Conditional Indexer)
与 ?. 类似,针对索引器操作。若左侧数组/集合为 null,则返回 null;否则执行索引操作。
using System;
public class Program {
public static void Main() {
string[] i = null;
string result = i?[1];
Console.WriteLine(result ?? "null"); // 输出: null
}
}
链式调用注意事项
链式使用时,若任意环节返回 null,则整个表达式直接返回 null,后续操作不会执行。以下示例展示差异:
using System;
public class Program {
public static void Main() {
string[] i = null;
// 无异常:遇到null后停止计算
Console.WriteLine(i?[1]?.Substring(0).Length);
// 抛出NullReferenceException:(i?[1]?.Substring(0))为null,调用Length时出错
Console.WriteLine((i?[1]?.Substring(0)).Length);
}
}
常见场景替换示例
1. 参数赋默认值
原代码:
// if(x == null) x = "str";
替换为:
x ??= "str";
2. 复杂条件判断
原代码:
string x;
if (i < 3)
x = y;
else {
if (z != null) x = z;
else z = "notnull";
}
替换为:
var x = i < 3 ? y : z ?? "notnull";
3. 避免空对象调用
原代码:
if (obj != null)
obj.Act();
替换为:
obj?.Act();
4. Dictionary 取值与赋值
原代码:
string result;
if (dict.ContainsKey(key)) {
if (dict[key] == null) result = "有结果为null";
else result = dict[key];
} else {
result = "无结果为null";
}
替换为:
var result = dict.TryGetValue(key, out var value)
? value ?? "有结果为null"
: "无结果为null";