我们使用?? Operator来计算针对空值的表达式,例如:
string foo = null;
string bar = "woooo";
string foobar= foo ?? bar ;
// Evaluates foobar as woooo
我们还使用了if
语句,如果与上面的表达式
string foo = null;
string bar = "woooo";
if(foo==null)
string foobar= "woooo" ;
// Evaluates foobar as woooo same as above
还有?: Ternary Operator ......
string foo = null;
string bar = "woooo";
string foobar= foo==null ? "woooo" : null ;
// Evaluates foobar as woooo same as above
我知道空合并在语法上是精确的,但哪一个在两者之间编译得更快,执行速度更快,为什么?
答案 0 :(得分:18)
你可能会问错误的问题。您不会选择使用一个而不是主要由于效率(尽管可能是次要问题),但由于效用。
你真的应该将??
与?:
进行比较,而不是if
进行比较,因为它们有不同的用途。是的,它们都是某种形式的“有条件”善良,但关键是??
和?:
都评估为一个值,而if
则没有,因此它们通常有不同的用途
例如,以下代码:
Console.WriteLine("The order} is for {1} product",
orderId, productId ?? "every");
使用if
写
if (productId == null)
{
Console.WriteLine("The order {0} is for every product",
orderId);
}
else
{
Console.WriteLine("The order {0} is for {1} product",
orderId, productId);
}
是的,你可以压缩到一个,但是你有一个临时变量等等:
if (productId == null)
{
productId = "every";
}
Console.WriteLine("The order {0} is for {1} product",
orderId, productId);
因此,你真的不应该比较两者,因为如果参数是??
,null
的点是评估值,而if
的点是执行不同的路径(不直接产生值。
所以,一个更好的问题可能是,为什么不这样做呢:
Console.WriteLine("The order {0} is for {1} product",
orderId, productId == null ? "every" : productId);
它们大致相同(都评估为一个值)并且没有流量控制那么多。
所以,让我们看看差异。让我们用三种方式编写这段代码:
// Way 1 with if
string foo = null;
string folder = foo;
if (folder == null)
{
folder = "bar";
}
// Way 2 with ? :
string foo2 = null;
var folder2 = foo2 != null ? foo2 : "bar";
// Way 3 with ??
string foo3 = null;
var folder3 = foo3 ?? "bar";
对于IF,我们得到以下IL:
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldnull
IL_0005: ceq
IL_0007: ldc.i4.0
IL_0008: ceq
IL_000A: stloc.1
IL_000B: ldloc.1
IL_000C: brtrue.s IL_0016
IL_000E: nop
IL_000F: ldstr "bar"
IL_0014: stloc.0
对于条件(?:),我们得到以下IL:
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: brtrue.s IL_000D
IL_0006: ldstr "bar"
IL_000B: br.s IL_000E
IL_000D: ldloc.0
IL_000E: nop
IL_000F: stloc.1
对于null-coallescing(??),我们得到这个IL:
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: dup
IL_0005: brtrue.s IL_000D
IL_0007: pop
IL_0008: ldstr "bar"
IL_000D: stloc.1
请注意每个连续的更简单? if
是更大的IL,因为它需要分支逻辑来处理单独的语句。 ?:
较小,因为它只是求值为一个值(不分支到其他语句),但仍需要加载操作数以与(null
)进行比较。
??
是最简单的,因为有一条IL指令用于与null
(与加载null
进行比较并与之进行比较。
SO 所有这些都说,你说IL的差异很小,可能会影响性能,也可能不会影响性能。无论如何,与程序中更密集的工作(数学,数据库,网络等)相比,这可能会有非常的重大差异。
因此,我建议选择 most 可读的那个,并且只有在通过分析找出当前方法不充分且瓶颈时才进行优化。
对我而言,使用?:
或??
的真正原因是您希望最终结果为值。也就是说,任何时候你都想写作:
if (someCondition)
x = value1;
else
x = value2;
然后我会使用条件(?:
),因为这是一个很好的简写。 x
根据此条件获取一个或另一个值...
然后我会再次使用??
并说同样如此,你想根据一个标识符的null
来为变量赋值。
所以if
非常适合流量控制,但如果您只是返回两个值中的一个或根据条件分配两个值中的一个,我会使用?:
或{{1酌情。
最后请记住这些内容如何在幕后实现(IL和相关性能)随.NET Framework的每个版本而变化(从我现在开始写这些内容时)都是如此接近可以忽略不计)。
因此,今天可能更快的可能明天不会更快。再说一次,我只想说最合适的一个,你发现最可读。
<强>更新强>
顺便提一下,对于真正的痴迷者,我比较了上面每个代码样本的10,000,000次迭代,这里是执行每个代码样本的总时间。看起来??
对我来说速度最快,但这些所以接近几乎无关紧要......
??
答案 1 :(得分:5)
他们应该编译到同一个IL,然后执行相同的。
即使他们没有,性能差异也可以忽略不计。除非我查看我的申请并且看到这些陈述需要花费大量时间,否则我甚至不会考虑这个。
始终使用最清晰的语法,除非您能证明它导致性能问题,而不是之前。