我最近发现我们可以使用??操作符以检查空值。请检查以下代码示例:
var res = data ?? new data();
这与
var res = (data==null) ? new data() : data ;
我检查了整个项目源存储库和其他一些开源项目。而且此
??
运算符从未使用过。我只是想知道背后是否有任何原因,例如性能问题或其他原因?
编辑:
我只是基于递归和Anton的评论更新了示例代码。粗心的错误。 :(
最佳答案
检查null时,null合并运算符更加清晰,这是其主要目的。也可以链接。
object a = null;
object b = null;
object c = new object();
object d = a ?? b ?? c; //d == c.
虽然该运算符仅限于null检查,但三元运算符则不是。例如
bool isQuestion = true;
string question = isQuestion ? "Yes" : "No";
我认为人们只是不了解空合并运算符,所以他们改用三元运算符。在大多数C风格语言中,三元都存在于C#之前,因此如果您不了解C#内在和/或使用其他语言编程,则三元是自然的选择。如果要检查是否为空,请使用空合并运算符,它是为此目的而设计的,并且IL进行了一些优化(将??与if if else进行比较)。
这是一个比较每种用法的示例
object a = null;
object b = null;
object c = null;
object nullCoalesce = a ?? b ?? c;
object ternary = a != null ? a : b != null ? b : c;
object ifThenElse;
if (a != null)
ifThenElse = a;
else if (b != null)
ifThenElse = b;
else if (c != null)
ifThenElse = c;
首先,只看一下空合并的语法,就更清楚了。三元确实令人困惑。现在让我们看一下IL
仅空合并
.entrypoint
.maxstack 2
.locals init (
[0] object a,
[1] object b,
[2] object c,
[3] object nullCoalesce)
L_0000: ldnull
L_0001: stloc.0
L_0002: ldnull
L_0003: stloc.1
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2
L_000a: ldloc.0
L_000b: dup
L_000c: brtrue.s L_0015
L_000e: pop
L_000f: ldloc.1
L_0010: dup
L_0011: brtrue.s L_0015
L_0013: pop
L_0014: ldloc.2
L_0015: stloc.3
L_0016: ldloc.3
L_0017: call void [mscorlib]System.Console::WriteLine(object)
L_001c: ret
仅三元
.entrypoint
.maxstack 2
.locals init (
[0] object a,
[1] object b,
[2] object c,
[3] object ternary)
L_0000: ldnull
L_0001: stloc.0
L_0002: ldnull
L_0003: stloc.1
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2
L_000a: ldloc.0
L_000b: brtrue.s L_0016
L_000d: ldloc.1
L_000e: brtrue.s L_0013
L_0010: ldloc.2
L_0011: br.s L_0017
L_0013: ldloc.1
L_0014: br.s L_0017
L_0016: ldloc.0
L_0017: stloc.3
L_0018: ldloc.3
L_0019: call void [mscorlib]System.Console::WriteLine(object)
L_001e: ret
如果只有那么
.entrypoint
.maxstack 1
.locals init (
[0] object a,
[1] object b,
[2] object c,
[3] object ifThenElse)
L_0000: ldnull
L_0001: stloc.0
L_0002: ldnull
L_0003: stloc.1
L_0004: newobj instance void [mscorlib]System.Object::.ctor()
L_0009: stloc.2
L_000a: ldloc.0
L_000b: brfalse.s L_0011
L_000d: ldloc.0
L_000e: stloc.3
L_000f: br.s L_001a
L_0011: ldloc.1
L_0012: brfalse.s L_0018
L_0014: ldloc.1
L_0015: stloc.3
L_0016: br.s L_001a
L_0018: ldloc.2
L_0019: stloc.3
L_001a: ldloc.3
L_001b: call void [mscorlib]System.Console::WriteLine(object)
L_0020: ret
IL不是我的强项之一,因此也许有人可以编辑我的答案并加以扩展。我本来要解释我的理论,但我不想让自己和他人感到困惑。这三个函数的LOC数量都相似,但是并非所有IL运算符都需要相同的时间长度来执行。