Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# “一个”中发生了什么;如果(..| |…)”则;及;如果(……)”;内部构造?_C#_If Statement - Fatal编程技术网

C# “一个”中发生了什么;如果(..| |…)”则;及;如果(……)”;内部构造?

C# “一个”中发生了什么;如果(..| |…)”则;及;如果(……)”;内部构造?,c#,if-statement,C#,If Statement,我只是想知道在“如果或”和“如果和”中会发生什么。我有一种感觉,它只是使用&&和| |,在内部,所有案例都构建为单个if语句 紧凑形式| |: if(a || b || c) { DoSomething(); } 潜在的内部形式: if(a) { DoSomething(); } else if(b) { DoSomething(); } else if(c) { DoSomething(); } if(a) { if(b) {

我只是想知道在“如果或”和“如果和”中会发生什么。我有一种感觉,它只是使用
&&
| |
,在内部,所有案例都构建为单个if语句

紧凑形式| |:

if(a || b || c)
{
    DoSomething();
}
潜在的内部形式:

if(a)
{
    DoSomething();
}    
else if(b)
{
    DoSomething();
}    
else if(c)
{
    DoSomething();
}
if(a)
{
    if(b)
    {
        if(c)
        {
            DoSomething();
        }
    }
}

紧凑形式&&:

if(a && b && c)
{
    DoSomething();
}
潜在的内部形式:

if(a)
{
    DoSomething();
}    
else if(b)
{
    DoSomething();
}    
else if(c)
{
    DoSomething();
}
if(a)
{
    if(b)
    {
        if(c)
        {
            DoSomething();
        }
    }
}
这两个例子的表现有什么不同吗


*编辑:将else添加到| |案例中

首先,
|
&
是。这意味着:

if(a || b || c)
    DoSomething();
如果
a
为真,
b
c
将不被计算

其次,您对
|
的实现是错误的:

if(a)
    DoSomething();
if(b)
    DoSomething();
if(c)
    DoSomething();
DoSomething()
最多会被调用3次

应该是:

if(a)
    DoSomething();
else if(b)
    DoSomething();
else if(c)
    DoSomething();
若要完成此操作,请在您的条件下选择较短的呼叫优先:

if(aShortFunctionToExecute() || aVeryVeryLongFunctionToExecute())
     DoSomething();
将比

if(aVeryVeryLongFunctionToExecute() || aShortFunctionToExecute())
     DoSomething();
因为


如果您反汇编以下代码:

private static void Main()
{
    if (a() && b() && c())
    {
        Console.WriteLine("DoSomething");
    }
}
bool a(){
    return true;
}
bool b(){
    return 3 % 2 == 1;
}
bool c(){
    return (3 % 2) / 1 == 1;
}
您将获得:

    if (a() && b() && c())
00000022  call        FFFFFFFFFFEE8D90 
00000027  mov         byte ptr [rbp+20h],al 
0000002a  movzx       eax,byte ptr [rbp+20h] 
0000002e  test        eax,eax 
00000030  je          000000000000005A 
00000032  call        FFFFFFFFFFEE8D98 
00000037  mov         byte ptr [rbp+21h],al 
0000003a  movzx       eax,byte ptr [rbp+21h] 
0000003e  test        eax,eax 
00000040  je          000000000000005A 
00000042  call        FFFFFFFFFFEE8DA0 
00000047  mov         byte ptr [rbp+22h],al 
0000004a  movzx       ecx,byte ptr [rbp+22h] 
0000004e  xor         eax,eax 
00000050  test        ecx,ecx 
00000052  sete        al 
00000055  mov         dword ptr [rbp+24h],eax 
00000058  jmp         0000000000000062 
0000005a  nop 
0000005b  mov         dword ptr [rbp+24h],1 
00000062  nop 
00000063  movzx       eax,byte ptr [rbp+24h] 
00000067  mov         byte ptr [rbp+2Fh],al 
0000006a  movzx       eax,byte ptr [rbp+2Fh] 
0000006e  test        eax,eax 
00000070  jne         0000000000000087 
        {
00000072  nop 
            Console.WriteLine("DoSomething");
00000073  mov         rcx,12603398h 
0000007d  mov         rcx,qword ptr [rcx] 
00000080  call        00000000577A82A0 
00000085  nop 
        }
if (a())
00000022  call        FFFFFFFFFFEE8D90 
00000027  mov         byte ptr [rbp+20h],al 
0000002a  movzx       ecx,byte ptr [rbp+20h] 
0000002e  xor         eax,eax 
00000030  test        ecx,ecx 
00000032  sete        al 
00000035  mov         dword ptr [rbp+24h],eax 
00000038  movzx       eax,byte ptr [rbp+24h] 
0000003c  mov         byte ptr [rbp+3Fh],al 
0000003f  movzx       eax,byte ptr [rbp+3Fh] 
00000043  test        eax,eax 
00000045  jne         00000000000000A4 
            if(b())
00000047  call        FFFFFFFFFFEE8D98 
0000004c  mov         byte ptr [rbp+28h],al 
0000004f  movzx       ecx,byte ptr [rbp+28h] 
00000053  xor         eax,eax 
00000055  test        ecx,ecx 
00000057  sete        al 
0000005a  mov         dword ptr [rbp+2Ch],eax 
0000005d  movzx       eax,byte ptr [rbp+2Ch] 
00000061  mov         byte ptr [rbp+3Fh],al 
00000064  movzx       eax,byte ptr [rbp+3Fh] 
00000068  test        eax,eax 
0000006a  jne         00000000000000A4 
                if(c())
0000006c  call        FFFFFFFFFFEE8DA0 
00000071  mov         byte ptr [rbp+30h],al 
00000074  movzx       ecx,byte ptr [rbp+30h] 
00000078  xor         eax,eax 
0000007a  test        ecx,ecx 
0000007c  sete        al 
0000007f  mov         dword ptr [rbp+34h],eax 
00000082  movzx       eax,byte ptr [rbp+34h] 
00000086  mov         byte ptr [rbp+3Fh],al 
00000089  movzx       eax,byte ptr [rbp+3Fh] 
0000008d  test        eax,eax 
0000008f  jne         00000000000000A4 
                    Console.WriteLine("DoSomething");
00000091  mov         rcx,125D3398h 
0000009b  mov         rcx,qword ptr [rcx] 
0000009e  call        00000000577B82A0 
000000a3  nop 
至于守则:

private static void Main()
{
    if (a())
        if(b())
            if(c())
                Console.WriteLine("DoSomething");
}
static bool a(){
    return true;
}
static bool b(){
    return 3 % 2 == 1;
}
static bool c(){
    return (3 % 2) / 1 == 1;
}
您将获得:

    if (a() && b() && c())
00000022  call        FFFFFFFFFFEE8D90 
00000027  mov         byte ptr [rbp+20h],al 
0000002a  movzx       eax,byte ptr [rbp+20h] 
0000002e  test        eax,eax 
00000030  je          000000000000005A 
00000032  call        FFFFFFFFFFEE8D98 
00000037  mov         byte ptr [rbp+21h],al 
0000003a  movzx       eax,byte ptr [rbp+21h] 
0000003e  test        eax,eax 
00000040  je          000000000000005A 
00000042  call        FFFFFFFFFFEE8DA0 
00000047  mov         byte ptr [rbp+22h],al 
0000004a  movzx       ecx,byte ptr [rbp+22h] 
0000004e  xor         eax,eax 
00000050  test        ecx,ecx 
00000052  sete        al 
00000055  mov         dword ptr [rbp+24h],eax 
00000058  jmp         0000000000000062 
0000005a  nop 
0000005b  mov         dword ptr [rbp+24h],1 
00000062  nop 
00000063  movzx       eax,byte ptr [rbp+24h] 
00000067  mov         byte ptr [rbp+2Fh],al 
0000006a  movzx       eax,byte ptr [rbp+2Fh] 
0000006e  test        eax,eax 
00000070  jne         0000000000000087 
        {
00000072  nop 
            Console.WriteLine("DoSomething");
00000073  mov         rcx,12603398h 
0000007d  mov         rcx,qword ptr [rcx] 
00000080  call        00000000577A82A0 
00000085  nop 
        }
if (a())
00000022  call        FFFFFFFFFFEE8D90 
00000027  mov         byte ptr [rbp+20h],al 
0000002a  movzx       ecx,byte ptr [rbp+20h] 
0000002e  xor         eax,eax 
00000030  test        ecx,ecx 
00000032  sete        al 
00000035  mov         dword ptr [rbp+24h],eax 
00000038  movzx       eax,byte ptr [rbp+24h] 
0000003c  mov         byte ptr [rbp+3Fh],al 
0000003f  movzx       eax,byte ptr [rbp+3Fh] 
00000043  test        eax,eax 
00000045  jne         00000000000000A4 
            if(b())
00000047  call        FFFFFFFFFFEE8D98 
0000004c  mov         byte ptr [rbp+28h],al 
0000004f  movzx       ecx,byte ptr [rbp+28h] 
00000053  xor         eax,eax 
00000055  test        ecx,ecx 
00000057  sete        al 
0000005a  mov         dword ptr [rbp+2Ch],eax 
0000005d  movzx       eax,byte ptr [rbp+2Ch] 
00000061  mov         byte ptr [rbp+3Fh],al 
00000064  movzx       eax,byte ptr [rbp+3Fh] 
00000068  test        eax,eax 
0000006a  jne         00000000000000A4 
                if(c())
0000006c  call        FFFFFFFFFFEE8DA0 
00000071  mov         byte ptr [rbp+30h],al 
00000074  movzx       ecx,byte ptr [rbp+30h] 
00000078  xor         eax,eax 
0000007a  test        ecx,ecx 
0000007c  sete        al 
0000007f  mov         dword ptr [rbp+34h],eax 
00000082  movzx       eax,byte ptr [rbp+34h] 
00000086  mov         byte ptr [rbp+3Fh],al 
00000089  movzx       eax,byte ptr [rbp+3Fh] 
0000008d  test        eax,eax 
0000008f  jne         00000000000000A4 
                    Console.WriteLine("DoSomething");
00000091  mov         rcx,125D3398h 
0000009b  mov         rcx,qword ptr [rcx] 
0000009e  call        00000000577B82A0 
000000a3  nop 
这有点长:它需要40条指令而不是31条指令


正如所指出的,性能还取决于条件为真的概率。以他为例:

如果
a
在99%的时间内失败,运行需要1秒,如果
b
99%的成功率和10秒的运行时间,超过100次尝试您将更快地将
b
放在第一位:

if(b || a) => 10s 99% ==> 100 runs will take 99*10+11 = 1001s
if(b || a) => 11s 1%

if(a || b) => 11s 99% ==> 100 runs will take 99*11+1 = 1090s
if(a || b) => 1s 1%

另外,我建议你读一读“”这本书,它很有趣

使用压缩形式,C#编译器发出的IL将不那么冗长,导致运行时需要处理的指令更少。发出的IL语句及其逻辑实际上是相同的,因此没有处理这种情况或某些特殊指令的内置支持(请记住,您可以将任何带有布尔结果的表达式放入
if

对于使用
|
运算符(调试生成)的压缩表单:

使用内部表单(考虑到您使用的是
else if
而不是
if
):

因此,有更多的指令来处理附加的
if
语句所需的所有跳转。因此,第一种形式更有效(实际上更可读:)

在性能方面(每种方法用10.000.000次迭代测量了10次,并删除了最高值和最低值,发布版本):

紧凑型:平均55ms

详细格式:平均56ms

所以根本没有什么大区别。

代码:

if(a)
    if(b)
        if(c)
            DoSomething();
是逻辑(但不是“实际”)等价物,用于:

if(a && b && c)
    DoSomething();
if(a || b || c)
    DoSomething();
至于
操作符,您有点搞错了。逻辑(但同样不是“实际”)等价物,用于:

if(a && b && c)
    DoSomething();
if(a || b || c)
    DoSomething();
将是:

if(a)
    DoSomething();
else if(b)
    DoSomething();
else if(c)
    DoSomething();
通过实际差异,我理解编译器引入的任何结果代码差异(有关详细信息,请参阅其他答案)。

和是条件运算符。它们也是操作符,就像你可能知道的其他操作符一样。(例如,
+
*
,…)

它们的行为类似于逻辑运算符,
|
&
。它们接收两个
bool
类型变量,并以这种方式返回
bool
值:

// If one of them is true, the return value is true. Otherwise, it's false.
true  | true  == true
true  | false == true
false | true  == true
false | false == false
// If both of them are true, the return value is true. Otherwise, it's false.
true  & true  == true
true  & false == false
false & true  == false
false & false == false
但是,对于条件运算符,有一点不同:短路

假设此代码:

bool func1() { .. }
bool func2() { .. }

bool b1 = func1() || func2();
bool b2 = func1() && func2();
如果
func1()
返回
true
b1
变为
true
,而不管
func2()
返回什么。因此,我们不需要调用
func2()
,实际上也不需要。如果
func1()。这种行为称为短路


现在,让我们想想你的例子

if (a || b || c)
    DoSomething();
等于

bool value = a || b || c;
if (value)
    DoSomething();
bool value = (a || b) || c;
if (value)
    DoSomething();
因为条件运算符的值是从左到右的,所以等于

bool value = a || b || c;
if (value)
    DoSomething();
bool value = (a || b) || c;
if (value)
    DoSomething();

它们的VB等价物可以更具描述性
|
在VB中是
OrElse
&

这些是条件运算符;也就是说,他们让控制子句-
如果在您的情况下-
根据需要评估条件,而不是总是评估所有条件

例如,在
if(a | | b)
中,如果
a
为真,那么
b
是什么并不重要;结果为真,因此不会对
b
进行计算,这将导致更快的执行

此功能也可以用作空检查机制
if(a!=null&&a.prop==somevalue)
将防止null引用异常,如果
a
为null,如果它不为null,将访问它的
prop
属性来评估第二个条件。

对于那些阅读C优于汇编的人,真正的内部形式更接近:

if(a) goto yes;
if(b) goto yes;
if(c) goto yes;
goto no;
yes:  DoSomething();
goto done;
no:   /* if there were an else it would go here */;
done: ;
为了

为了


这是因为实际的指令是条件分支——在内部形式中,
if
不可能与块相关联,嵌套的
if
,或者实际上除了
goto
之外的任何东西都不可能与块相关联,为什么不自己检查一下呢?
|
&
顺便说一下。严格来说,您对
|
的解释是错误的-您提供的代码将包含
DoSomething()执行三次。考虑<代码> < <代码> >代码> b>代码>和<代码> c>代码>是很长时间以来返回<代码> BOOL 的昂贵方法。那么,很清楚为什么短路操作员应该优先于连续的
if
s。但是,即使它们不是方法,但是变量
DoSomething()
也会执行三次而不是一次,如果所有的都是真的,这是完全不同的。这个问题的一般形式(问了很多问题,例如,“我应该为结构使用memcpy吗?”)通常归结为“我能确定吗?”