首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Null coalesce、Ternary或If语句中哪一个运行得更快

Null coalesce、Ternary或If语句中哪一个运行得更快
EN

Stack Overflow用户
提问于 2012-11-15 03:01:27
回答 1查看 4.7K关注 0票数 7

我们使用?? Operator根据空值对表达式求值,例如:

代码语言:javascript
复制
string foo = null;
string bar = "woooo";
string foobar= foo ?? bar ; 
// Evaluates foobar as woooo

我们还使用了if语句,如果与上面的表达式一起使用,它的工作方式相同

代码语言:javascript
复制
string foo = null;
string bar = "woooo";
if(foo==null)
   string foobar=   "woooo" ;
// Evaluates foobar as woooo same as above

还有?: Ternary Operator..。

代码语言:javascript
复制
string foo = null;
string bar = "woooo";    
string foobar= foo==null ? "woooo" : null ;
// Evaluates foobar as woooo same as above

我知道null合并在语法上是精确的,但是在这两个中哪一个编译得更快,执行得更快,为什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-11-15 03:15:26

你可能问错了问题。您不会选择使用一个而不是另一个,主要是因为效率(尽管这可能是次要的问题),而是出于实用性。

实际上,您应该将???:进行比较,而不是将其与if进行比较,因为它们有不同的目的。是的,它们都是某种形式的“条件”好,但关键是???:都求值,而if不求值,因此它们通常有不同的用途。

例如,以下代码:

代码语言:javascript
复制
Console.WriteLine("The order} is for {1} product",
    orderId, productId ?? "every");

使用if编写起来会更加笨拙

代码语言:javascript
复制
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);
}

是的,你可以压缩成一个,但之后你会有一个临时变量,等等:

代码语言:javascript
复制
if (productId == null)
{
    productId = "every";
}

Console.WriteLine("The order {0} is for {1} product",
    orderId, productId);

因此,您真的不应该比较这两者,因为如果参数为null,则??的要点是计算一个值,而if的要点是执行不同的路径(而不是直接产生一个值。

因此,一个更好的问题可能是,为什么不这样做:

代码语言:javascript
复制
Console.WriteLine("The order {0} is for {1} product",
    orderId, productId == null ? "every" : productId);

这几乎是相同的(两者的计算结果都是一个值),但对于流控制来说就不一样了。

那么,让我们来看看它们之间的区别。让我们以三种方式编写这段代码:

代码语言:javascript
复制
// 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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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方面的很小的差异,这可能会也可能不会影响性能。无论如何,与程序中更密集的工作(数学、数据库、网络等)相比,这可能会使有很小的主要区别。

因此,我建议选择可读性最好的方法,只有在通过分析发现当前方法不足和瓶颈时才进行优化。

对我来说,使用?:??的真正原因是您希望最终结果是一个值。也就是说,任何时候你想写:

代码语言:javascript
复制
if (someCondition)
    x = value1;
else 
    x = value2;

然后我会使用条件(?:),因为这是一个很好的简写。x根据此条件获取一个或另一个值...

然后我用??更进一步,假设这也是真的,你想要根据一个身份的null-ness给一个变量赋值。

因此,if对于流量控制非常有用,但如果只是返回两个值中的一个,或者根据条件分配两个值中的一个,我会适当地使用?:??

最后,记住这些东西是如何在幕后实现的(IL和相关的性能)会随着.NET框架的每次修订而变化(在我写这篇文章的时候,它们都是如此接近,以至于可以忽略不计)。

因此,今天可能更快的东西明天可能不会更快。所以我再说一遍,我只想用最适合的,你会发现最具可读性的。

更新

顺便说一句,对于真正着迷的人,我比较了上面每个代码样本的10,000,000次迭代,这里是执行每个代码样本的总时间。看起来??对我来说是最快的,但它们又是如此接近,几乎无关紧要……

代码语言:javascript
复制
10,000,000 iterations of:
?: took: 489 ms, 4.89E-06 ms/item.
?? took: 458 ms, 4.58E-06 ms/item.
if took: 641 ms, 6.41E-06 ms/item.
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13385503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档