如果和返回是有效的,或者是否有效/推荐?

时间:2018-02-13 06:03:45

标签: c#

有人可以告诉我以下哪两个片段有效/推荐以及为什么?

private void method1()
{
    if(condition)
    {
    //some code to be executed when the condition is met
    return;
    }
    //some code to be executed when the condition is not met
}

private void method2()
{
    if(condition)
    {
     //some code to be executed when the condition is met
    }
    else
    {
     //some code to be executed when the condition is not met
    }
}

以下问题中给出的答案在效率或推荐实践方面没有提到任何与我的问题有关的问题,问题看起来只是在询问什么是正确的。

In an If-Else Statement for a method return, should an Else be explicitly stated if it can instead be implicitly followed?

3 个答案:

答案 0 :(得分:2)

就执行速度而言,可能不会有任何值得思考的差异。

就可读性而言,我建议你将问题放在另一个层面,看看它在哪里。这两个例子遵循你的两个模式,但是对于一个不那么微不足道的问题。哪个更容易阅读?

void Example1()
{
    if (a)
    {
        if (b)
        {
            if (c)
            {
                D();
            }
        }
        else
        {
            Y();
        }
    }
    else
    {
        X();
    }
}

void Example2()
{
    if (!a) 
    {
        X();
        return;
    }
    if (!b)
    {
        Y();
        return;
    }
    if (!c) return;
    D();
}

第一个模式最终会使用Arrow,而第二个模式会使用Guard。箭头被认为是一种反模式。

当你展平箭头以使用守卫时,你减少cyclomatic complexity,减少代码长度,减少滚动查看完整代码块的需要,并减少理解其含义所需的心理操作次数平均代码行。

第二种方法在几乎所有方面都是客观上​​更好的,除了非常简单的逻辑之外,else可以更清楚地传达你想要完成的事情。

答案 1 :(得分:2)

性能完全没有区别。在IL中比较这两种方法:

   .method private hidebysig static void  Method1() cil managed
  {
    // 
    .maxstack  2
    .locals init (bool V_0)
    IL_0000:  nop
    IL_0001:  ldsfld     int32 Program::condition // Push condition onto stack
    IL_0006:  ldc.i4.1 // Load constant integer 1
    IL_0007:  ceq      // Check if they equal
    IL_0009:  ldc.i4.0 // Load constant integer 0
    IL_000a:  ceq      // Check if previous compare returned true
    IL_000c:  stloc.0  
    IL_000d:  ldloc.0
    IL_000e:  brtrue.s   IL_0013 // If true then short branch to return

    IL_0010:  nop
    IL_0011:  br.s       IL_0013 // Else just to return (the same as IL_000e)

    IL_0013:  ret
  } // end of method Program::Method1

  .method private hidebysig static void  Method2() cil managed
  {
    // 
    .maxstack  2
    .locals init (bool V_0)
    IL_0000:  nop
    IL_0001:  ldsfld     int32 Program::condition
    IL_0006:  ldc.i4.1
    IL_0007:  ceq
    IL_0009:  ldc.i4.0
    IL_000a:  ceq
    IL_000c:  stloc.0
    IL_000d:  ldloc.0
    IL_000e:  brtrue.s   IL_0014

    IL_0010:  nop
    IL_0011:  nop
    IL_0012:  br.s       IL_0016  // We branch but in release I doubt the branch would still exist at runtime.

    IL_0014:  nop
    IL_0015:  nop
    IL_0016:  ret
  } // end of method Program::Method2

这些nop指令仅可见,因为我在调试模式下运行它。它们不会在发布中存在。可复制的代码:

public static void Main(string[] args)
{
    Method1();
    Method2();
}
static int condition = 1;

private static void Method1()
{
    if(condition == 1)
    {
        return;
    }
}

private static void Method2()
{
    if(condition == 1)
    {
    }
    else
    {
    }
}

在优化应用程序时,首先要看一下真正的瓶颈是什么。找出导致最长延迟的原因并开始优化。您目前要做的是称为过早优化。因此,您的代码变得不那么可读,可能更慢并且更容易出错。

答案 2 :(得分:1)

如果您有 MSIL强迫症(强迫症),您可以通过不使用OpCodes.Nop来保存自己1 else

OpCodes.Nop Field

  

如果修补了操作码,则填充空格。没有有意义的操作   虽然可以消耗处理周期,但仍会执行。

<强>代码

private static  int Method1(bool condition)
{
   if (condition)
   {
      return 1+1;
   }
   return 2 + 2;
}

<强> MSIL

IL_0000: nop          

IL_0001: ldarg.0      // condition
IL_0002: stloc.0      // V_0

IL_0003: ldloc.0      // V_0
IL_0004: brfalse.s    IL_000b

IL_0006: nop          

IL_0007: ldc.i4.2     
IL_0008: stloc.1      // V_1
IL_0009: br.s         IL_000f

IL_000b: ldc.i4.4     
IL_000c: stloc.1      // V_1
IL_000d: br.s         IL_000f

IL_000f: ldloc.1      // V_1
IL_0010: ret  

<强>代码

private static int Method2(bool condition)
{
   if (condition)
   {
      return 1 + 1;
   }
   else
   {
      return 2 + 2;
   }
}

<强> MSIL

IL_0000: nop          

IL_0001: ldarg.0      // condition
IL_0002: stloc.0      // V_0

IL_0003: ldloc.0      // V_0
IL_0004: brfalse.s    IL_000b

IL_0006: nop          

IL_0007: ldc.i4.2     
IL_0008: stloc.1      // V_1
IL_0009: br.s         IL_0010

IL_000b: nop          

IL_000c: ldc.i4.4     
IL_000d: stloc.1      // V_1
IL_000e: br.s         IL_0010

IL_0010: ldloc.1      // V_1
IL_0011: ret