我最近发现我们可以使用??运算符检查空值。请检查以下代码示例:
var res = data ?? new data();
这与
完全相似 var res = (data==null) ? new data() : data ;
我检查了整个项目源代码库和一些其他开源项目。这个??
运算符从未被使用过。
我只是想知道这背后有什么理由,比如性能问题还是什么?
修改
我刚刚根据recursive&的评论更新了我的示例代码。安东。粗心大意是一个错误。 :(
答案 0 :(得分:58)
在检查null时,null coalesce运算符更清晰,这是它的主要目的。它也可以链接。
object a = null;
object b = null;
object c = new object();
object d = a ?? b ?? c; //d == c.
虽然该运算符仅限于空检查,但三元运算符不是。例如
bool isQuestion = true;
string question = isQuestion ? "Yes" : "No";
我认为人们只是不知道null coalesce运算符,所以他们使用三元运算符代替。在大多数C风格语言中C#之前存在三元组,所以如果你不知道C#里面和外面和/或你用另一种语言编程,那么三元是一个自然的选择。但是,如果要检查null,请使用null coalesce运算符,它是为此设计的,并且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;
首先,看一下null coalesce的语法,它更清晰。三元真的很混乱。现在让我们看一下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的LOC数相似,但并非所有IL运算符都需要相同的执行时间。
答案 1 :(得分:12)
??运算符(也称为null-coalescing operator)比三元运算符更为人所知,因为它首次使用.NET 2.0和Nullable Types。不使用它的原因可能包括没有意识到它存在,或者更熟悉三元运算符。
也就是说,检查null并不是三元运算符唯一有用的东西,所以它不是它的替代品,更像是一个非常特殊的需求的更好选择。 :)
答案 2 :(得分:6)
答案 3 :(得分:4)
基于Bob's回答
public object nullCoalesce(object a, object b, object c)
{
return a ?? b ?? c;
}
public object ternary(object a, object b, object c)
{
return a != null ? a : b != null ? b : c;
}
public object ifThenElse(object a, object b, object c)
{
if (a != null)
return a;
else if (b != null)
return b;
else
return c;
}
......这是来自发布版本的IL ......
.method public hidebysig instance object nullCoalesce(
object a,
object b,
object c) cil managed
{
.maxstack 8
L_0000: ldarg.1
L_0001: dup
L_0002: brtrue.s L_000b
L_0004: pop
L_0005: ldarg.2
L_0006: dup
L_0007: brtrue.s L_000b
L_0009: pop
L_000a: ldarg.3
L_000b: ret
}
.method public hidebysig instance object ternary(
object a,
object b,
object c) cil managed
{
.maxstack 8
L_0000: ldarg.1
L_0001: brtrue.s L_000a
L_0003: ldarg.2
L_0004: brtrue.s L_0008
L_0006: ldarg.3
L_0007: ret
L_0008: ldarg.2
L_0009: ret
L_000a: ldarg.1
L_000b: ret
}
.method public hidebysig instance object ifThenElse(
object a,
object b,
object c) cil managed
{
.maxstack 8
L_0000: ldarg.1
L_0001: brfalse.s L_0005
L_0003: ldarg.1
L_0004: ret
L_0005: ldarg.2
L_0006: brfalse.s L_000a
L_0008: ldarg.2
L_0009: ret
L_000a: ldarg.3
L_000b: ret
}
答案 4 :(得分:2)
其中一个原因(正如其他人已经触及过的那样)可能是缺乏意识。它也可能(如我自己的情况),希望保持尽可能多地在代码库中执行类似操作的方法的数量。所以我倾向于使用三元运算符来处理所有紧凑的if-a-condition-is-met-do-this-otherwise-do-situation。
例如,我发现以下两个陈述在概念层面上相似:
return a == null ? string.Empty : a;
return a > 0 ? a : 0;
答案 5 :(得分:1)
我认为这只是其他语言的习惯。据我所知, ??运算符不用于任何其他语言。
答案 6 :(得分:0)
我会想到相当于
var res = data ?? data.toString();
将是
var res = (data!=null) ? data : data.toString();