速记IF vs普通If [英] Shorthand IF vs normal If

查看:90
本文介绍了速记IF vs普通If的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

使用IF..Then..Else语句的简写/紧凑"形式时,是否有任何特定的性能提高/降低,而不是"long"形式,或者在使用其中一种时需要记住的其他事项两种形式中的哪一种?

示例:

Hi all,

Are there any specific performance increases/decreases when using the "shorthand/compact" form of the IF..Then..Else statement, as opposed to the "long" form, or anything else that one needs to keep in mind when using either of the two forms?

Example:

callCount = paidEntries >= unpaidEntries ? paidEntries : unpaidEntries;




相反



As Opposed to

if (paidEntries >= unpaidEntries)
{
   callCount = paidEntries;
}
else
{
   callCount = unpaidEntries;
}

推荐答案

三元运算符的性能不应与写得相当的if/else语句有所不同...它们很可能解析为在抽象语法树中具有相同的表示形式,并经过相同的优化等.

但是,您表达问题的方式表明您对它们不满意.关键是真正的本地化,避免重复重复同一语句/函数调用的其他部分.
The ternary operator shouldn''t differ in performance from a well-written equivalent if/else statement... they may well resolve to the same representation in the Abstract Syntax Tree, undergo the same optimisation etc..

But, the way you phrase your question suggests you have an aversion to them. The point is really localisation, and avoiding redundantly repeating other parts of the same statements/function-calls.


猜测工作几乎没有意义.让我们分解一下.速记:
Guesswork is pretty much pointless. Let''s disassemble it. Shorthand:
//000006:         static void Main(string[] args) {
    IL_0000:  nop
//000008:             int callCount, paidEntries = 1, unpaidEntries = 2;
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.1
    IL_0003:  ldc.i4.2
    IL_0004:  stloc.2
//000009:             callCount = paidEntries >= unpaidEntries ? paidEntries : unpaidEntries;
    IL_0005:  ldloc.1
    IL_0006:  ldloc.2
    IL_0007:  bge.s      IL_000c

    IL_0009:  ldloc.2
    IL_000a:  br.s       IL_000d

    IL_000c:  ldloc.1
    IL_000d:  stloc.0
//000010:             System.Console.WriteLine(callCount); // I also printed it, to avoid optimizing out
    IL_000e:  ldloc.0
    IL_000f:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_0014:  nop
//000011:         }
    IL_0015:  ret
  } // end of method Program::Main



使用if-else块:



With if-else block:

//000006:         static void Main(string[] args) {
    IL_0000:  nop
//000008:             int callCount, paidEntries = 1, unpaidEntries = 2;
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.1
    IL_0003:  ldc.i4.2
    IL_0004:  stloc.2
//000010:             if (paidEntries >= unpaidEntries)
    IL_0005:  ldloc.1
    IL_0006:  ldloc.2
    IL_0007:  clt
    IL_0009:  stloc.3
    IL_000a:  ldloc.3
    IL_000b:  brtrue.s   IL_0011

//000011:                 callCount = paidEntries;
    IL_000d:  ldloc.1
    IL_000e:  stloc.0
    IL_000f:  br.s       IL_0013

//000012:             else
//000013:                 callCount = unpaidEntries;
    IL_0011:  ldloc.2
    IL_0012:  stloc.0
//000014:             System.Console.WriteLine(callCount);
    IL_0013:  ldloc.0
    IL_0014:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_0019:  nop
//000015:         }
    IL_001a:  ret
  } // end of method Program::Main



不,这不一样!如果使用if-else块,则涉及更多代码,这或多或少是可以解释的.它可能包含更多更通用的代码.

我还尝试了经过优化的选项,并获得了相同的结果.

我还认为速记版本会更快一些,但是最好使用System.Diagnostics.Stopwatch进行计时,以确保准确性.
任何人? :-)

—SA



No, this is not the same! With if-else block, some more code is involved, which is more or less explainable; it can potentially include more of more general code.

I also tried optimized options, with identical results.

I also think that the shorthand version will be a bit faster, but it''s the best to do the timing using System.Diagnostics.Stopwatch, for accuracy.
Anyone? :-)

—SA


我会说这很大程度上是样式问题-性能很可能不是问题.
...这是火焰战争的重要话题,虽然;-)...

例如.参见 http://www.google.de/search?q=ternary+operator+harmful+evil [^ ]

除了样式问题,关于生成的IL代码(大小等)和JIT行为(在执行之前编译了哪些方法),以下两段代码有多近?

纯文本"if-else" 三元
I would say it''s very much a question of style - performance is most likely not an issue.
...and it''s a great topic for flame wars, though ;-)...

E.g. see http://www.google.de/search?q=ternary+operator+harmful+evil[^]

Beside the style question, how close are following two pieces of code with respect of generated IL code (size, etc.) and JIT behaviour (which method calles are compiled before execution)?

plain "if-else"ternary
static void Main(string[] args)
{
    object obj;
    if (args.Length > 0)
    {
        obj = CaseA();
    }
    else
    {
        obj = CaseB();
    }
    Console.WriteLine(obj);
}



static void Main(string[] args)
{
    object obj = args.Length > 0
        ? CaseA()
        : CaseB();
    Console.WriteLine(obj);
}




好消息:IL代码彼此非常接近,并且JIT仅编译实际被调用的情况-在这两种情况下,另一种情况都不是JIT编译的.

详细说明:

纯文本"if-else" 三元




The good news: the IL code is very close to each other, and the JIT only compiles the case that actually gets called - in both cases, the other case is not JIT compiled.

The details:

plain "if-else"ternary

.method ...Main(string[] args)...
{
  .entrypoint
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] object obj)
  IL_0000:  ldarg.0
  IL_0001:  ldlen
  IL_0002:  conv.i4
  IL_0003:  ldc.i4.0
  IL_0004:  ble.s    IL_000e

  IL_0006:  call     ...::CaseA()
  IL_000b:  stloc.0
  IL_000c:  br.s     IL_0014

  IL_000e:  call     ...::CaseB()
  IL_0013:  stloc.0
  IL_0014:  ldloc.0
  IL_0015:  call     ...::WriteL...
  IL_001a:  ret
} // end of method Program::Main



.method ...Main(string[] args)...
{
  .entrypoint
  // Code size       26 (0x1a)
  .maxstack  2
  .locals init ([0] object obj)
  IL_0000:  ldarg.0
  IL_0001:  ldlen
  IL_0002:  conv.i4
  IL_0003:  ldc.i4.0
  IL_0004:  bgt.s    IL_000d

  IL_0006:  call     ...::CaseB()
  IL_000b:  br.s     IL_0012

  IL_000d:  call     ...::CaseA()
  IL_0012:  stloc.0
  IL_0013:  ldloc.0
  IL_0014:  call     ...::WriteL...
  IL_0019:  ret
} // end of method Program::Main




三元数更接近C#代码:比较与条件中所述的相同(在if-else情况下,比较将转换为对数).唯一的不同是stloc.0指令在三进制情况下仅可用一次,在if-else情况下,每个分支都有其自己的stloc.0语句.

如果您对这两种情况都进行遍历,则语句的数量和种类是相同的,因此,不会对速度造成影响,对于三进制情况,代码长度只会小得多.

如果查看IL代码并知道JIT仅编译有效执行的调用",那么您还会看到在三元情况下,只有有效调用的函数才编译JIT.

您还可以通过
尝试这种JIT行为




The ternary is a bit closer to the C# code: the comparison is the same as stated in the condition (where in the if-else case, the comparison is converted to the oposite). The only other difference is that the stloc.0 instruction is available only once in the ternary case, where in the if-else case, each branch has its own stloc.0 statement.

If you walk through for both cases both branches, the number and kind of statements are identical, so, no speed impact given, only a sligtly smaller code size for ternary case.

If looking at the IL code and knowing that the JIT only compiles the "call" that is effectively executed, then you see that also in the ternary case, only the effectively called functions get JIT compiled.

You can also try out this JIT behaviour by

// assembly LibA.dll
namespace LibA
{
    public class ClassA
    {
    }
}

// assembly main.exe
...
public static object CaseA()
{
    return new LibA.ClassA();
}
public static object CaseB()
{
    return "CaseB";
}



编译该文件并从cmd.exe提示符下执行if-else主程序和带有/不带参数的三元主程序(请参阅基于args数组的长度进行决策的主程序). />
在这两种情况下,程序都将执行.

现在,删除main.exe旁边的LibA.dll,以便main.exe尝试查找时不会找到该库.

在不使用args的情况下运行main.exe->好的.
使用args运行main.exe->加载程序异常(因为它尝试JIT编译CaseA()并且该函数尝试获取LibA.ClassA).

IE. CaseA()仅在真正使用时才编译,否则,不会检测到缺少的引用.

干杯
安迪

PS:我不时使用三元运算符,我认为它很简洁,易于阅读和维护.



Compile that and execute from the cmd.exe prompt for the if-else main program and for the ternary main program with/without an argument (see the Main program where the decision is made based on the length of the args array).

In both cases the program executes.

Now remove the LibA.dll beside the main.exe so that the main.exe does not find that library if it would try to.

Run main.exe without args --> ok.
Run main.exe with args --> loader exception (since it tries to JIT compile CaseA() and that function tries to get LibA.ClassA).

I.e. the CaseA() is only compiled when really used, otherwise, the missing reference is not detected.

Cheers
Andi

PS: I use now and then the ternary operator, where I consider it concise and easy enough to read and maintain.


这篇关于速记IF vs普通If的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆