否则还是回来?

时间:2010-05-17 11:39:42

标签: c# .net

以下两项中哪一项最适合表现和标准练习。 .NET内部如何处理这两个代码片段?

代码1

If(result)
{
  process1();
}
else
{
  process2();
}

或代码2

If(result)
{
   process1();
   return;
}
process2();

19 个答案:

答案 0 :(得分:32)

就我个人而言,我总是希望尽快回来,所以我会选择:

if (result)
{
    // do something
    return;
}

// do something if not result

关于性能,我怀疑它们是否具有任何优势,它实际上取决于可读性和个人品味。我假设.NET会优化你的第一个代码块,如上所述。

答案 1 :(得分:25)

在任何正常情况下,性能差异(如果有的话)都可以忽略不计。

一种标准做法(除此之外)是尝试从方法中保留一个退出点,以便讨论第一种选择。

中间的return的实际实现最有可能跳转到方法的末尾,其中包含方法的堆栈帧的代码是,所以它很可能是最终的两个代码的可执行代码相同。

答案 2 :(得分:23)

我认为'单一退出点'被高估了。过于教条地坚持它会导致一些非常复杂的代码,它们应该有多个出口点,或者分成更小的方法。

我想说两者之间的选择取决于语义。

'如果某些条件为真则执行此操作,否则执行此操作'完美映射到if-else。

if (isLoggedIn) {
    RedirectToContent();
} else {
    RedirectToLogin();
}

'如果某些条件然后进行一些清理并拯救'更好地映射到代码2.这称为保护模式。这使得代码的主体尽可能正常,清晰,整洁,不必要的缩进。它通常用于验证参数或状态(检查某些内容是否为空,或某些内容是否已缓存,类似于此类)。

if (user == null) {
    RedirectToLogin();
    return;
}

DisplayHelloMessage(user.Name);

在同一个项目中看到这两种形式并不少见。正如我所说,使用哪种方法取决于你要传达的内容。

答案 3 :(得分:4)

如果有公共代码,则需要在if / else块之后执行,然后选项1。

如果if-else块是函数中的最后一件事,那么选项2。

我个人总是使用选项1.如果有一个返回状态,它会在else块

之后出现

答案 4 :(得分:3)

如果你删除第二个版本的剩余代码周围的大括号,那正是我使用的。我更倾向于使函数的早期验证部分显而易见,然后我就可以开始工作了。

话虽如此,这是一个意见问题。只要你对它保持一致,选择一个并坚持下去。

编辑关于性能,发出的IL完全相同。选择一种或另一种风格,也不会受到任何惩罚。

答案 5 :(得分:3)

它们都将编译为相同的IL for Release模式(在Debug中可能会有一些不同的Nop操作数。)因此没有性能差异。这完全取决于您和您的团队如何感觉代码更易于阅读。

我曾经在营地反对提前退出,但现在我觉得它可以使代码更容易遵循。

// C#
public static void @elseif(bool isTrue)
{
    if (isTrue)
        Process1();
    else
        Process2();
}
// IL
.method public hidebysig static void  elseif(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::elseif


// C#
public static void @earlyReturn(bool isTrue)
{
    if (isTrue)
    {
        Process1();
        return;
    }
    Process2();
}
// IL
.method public hidebysig static void  earlyReturn(bool isTrue) cil managed
{
  // Code size       15 (0xf)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  brfalse.s  IL_0009
  IL_0003:  call       void elseif.Program::Process1()
  IL_0008:  ret
  IL_0009:  call       void elseif.Program::Process2()
  IL_000e:  ret
} // end of method Program::earlyReturn

答案 6 :(得分:2)

不能说性能,但代码1看起来更清晰,更符合逻辑。跳出if块中间的函数看起来很混乱,很容易被忽视。

答案 7 :(得分:2)

以下是对保护条款的一些补充说明:http://www.c2.com/cgi/wiki?GuardClause

我认为没有提到的一个术语我认为很重要 - 保护条款的目的是提高可读性。单一退出方法可以倾向于“箭头”代码(其中语句的嵌套构成箭头)。

答案 8 :(得分:1)

这两种风格都是司空见惯的,宗教战争已经在他们身上展开。 : - )

我通常这样做:

  • 如果测试表达方法合同语义,例如检查输入参数的有效性,然后选择选项2。
  • 否则,请选择选项1.

然而,可以说更重要的规则是“对于下一个查看代码的开发人员来说,哪个更具可读性和/或可维护性?”。

正如其他人所说,性能差异可以忽略不计。

答案 9 :(得分:1)

我认为你不应该担心这里的表现。在这种情况下,可读性和可维护性更为重要。

坚持一个常规出口点是一种很好的做法。

然而,有时多次返回只会使代码更清晰,特别是当您在代码开头附近进行了大量测试时(即检查所有输入参数是否格式正确),其中'if -true'应该导致回归。

即:

if (date not set) return false;
age = calculateAgeBasedOnDate();
if (age higher than 100) return false;
...lots of code...
return result;

答案 10 :(得分:1)

我会使用Code 1,因为如果我在if语句之后添加一些内容,我仍然肯定它会执行,而我不需要记住删除return子句来自Code 2

答案 11 :(得分:1)

返回将导致代码从if语句所在的任何方法返回,不再执行任何代码。没有返回的语句将简单地从if语句中删除。

答案 12 :(得分:0)

我认为第二种选择对于许多条件(例如验证)的情况更好。 如果你在这些情况下使用第一个,你会得到丑陋的缩进。

 if (con){
    ...
    return;
 }
 if (other con){
    ...
    return;
 }
 ...
 return;

答案 13 :(得分:0)

我倾向于有单点退出,这在多线程环境中实现锁时非常有用,以确保释放锁。第一次实施时,更难做到。

答案 14 :(得分:0)

我倾向于从函数中退出多个点。我个人认为它更清晰,在某些情况下它可以更快。如果您检查某些内容然后返回该程序将不执行任何左命令。 然后再次如HZC所说,如果您处理多线程应用程序,那么您最好的镜头可能正在使用您的第一个示例。无论如何,对于一小段代码,它不会有任何区别(可能甚至对于一些较大的代码也没有)。最重要的是你写下你感觉舒服的方式。

答案 15 :(得分:0)

我认为没关系。你应该考虑可读性,我认为越少越好。所以我会返回没有最后2个括号(见下面的示例)。 在写这样的东西时,请不要考虑性能,它不会给你任何东西,但在过早的阶段会给你太多的复杂性。

if(result)
{
  process 1
  return;
}

process 2

答案 16 :(得分:0)

如果我不得不说,我会说更好的做法是if-else而不是“隐含的”其他。原因在于,如果其他人修改了您的代码,他们可以通过浏览来轻松捕获它。

我记得编程世界中有一个关于你的代码中是否应该有多个return语句的争论。可以说它是一个非常混乱的根源,因为如果你在“if”语句中有多个循环,并且有条件返回,那么它可能会引起一些混乱。

我通常的做法是使用if-else语句和单个return语句。

例如,

type returnValue;
if(true)
{
 returnValue = item;
}
else
 returnValue = somethingElse;

return returnValue;

在我看来,上面的内容更具可读性。然而,情况并非总是如此。有时最好在if语句的中间使用return语句,特别是如果它需要一个棘手的return语句。

答案 17 :(得分:0)

取决于“结果”,“process1”和“process2”是什么。

如果process2是“结果”为假的逻辑结果;你应该去代码1.如果process1和process2是等价的替代品,这是最易读的模式。

if (do_A_or_B = A)
  A()
else
  B()

如果结果是某些“禁止”状态而“process1”仅仅是在这种情况下需要清理的话,你应该选择代码2.如果“process2”是函数的主要动作,那么它是最易读的模式。 / p>

if (NOT can_do_B)
{
  A() 
  return
}

B()

答案 18 :(得分:0)

这取决于具体情况。

如果这是在计算值时的函数,则在您拥有它时立即返回该值(选项2)。您正在展示您已经完成了所需的所有工作,并且正在离开。

如果这是代码是程序逻辑的一部分,那么最好尽可能精确(选项1)。看着选项1的人会知道你的意思(做这个或那个),其中选项2可能是一个错误(在这种情况下这样做,然后总是这样做 - 我会为你纠正它!)。之前就已经过了。

编译时这些通常是相同的,但我们对性能不感兴趣。这是关于可读性和可维护性。