例如,当我在我的代码上运行ReSharper时:

    if (some condition)
    {
        Some code...            
    }

ReSharper给了我上面的警告(反转“if”语句以减少嵌套),并建议以下更正:

   if (!some condition) return;
   Some code...

我想知道为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。


当前回答

就我个人而言,我倾向于只有一个退出点。如果您保持方法的简短和切中要害,这很容易实现,并且它为下一个处理您的代码的人提供了可预测的模式。

eg.

 bool PerformDefaultOperation()
 {
      bool succeeded = false;

      DataStructure defaultParameters;
      if ((defaultParameters = this.GetApplicationDefaults()) != null)
      {
           succeeded = this.DoSomething(defaultParameters);
      }

      return succeeded;
 }

如果您只是想在函数退出之前检查函数中某些局部变量的值,这也是非常有用的。您所需要做的就是在最终返回值上放置一个断点,并保证能够命中它(除非抛出异常)。

其他回答

我的想法是“在函数中间”的返回不应该那么“主观”。 原因很简单,以下面的代码为例:

    function do_something( data ){

      if (!is_valid_data( data )) 
            return false;


       do_something_that_take_an_hour( data );

       istance = new object_with_very_painful_constructor( data );

          if ( istance is not valid ) {
               error_message( );
                return ;

          }
       connect_to_database ( );
       get_some_other_data( );
       return;
    }

也许第一个“回报”不是那么直观,但这是真正的储蓄。 有太多关于干净代码的“想法”,只是需要更多的实践来摆脱他们“主观的”坏想法。

它不仅影响美观,而且还阻止了代码嵌套。

它实际上也可以作为确保数据有效的前提条件。

这是一个有点宗教的争论,但我同意ReSharper的观点,你应该更喜欢少嵌套。我相信这超过了一个函数有多条返回路径的缺点。

减少嵌套的关键原因是为了提高代码的可读性和可维护性。请记住,将来会有许多其他开发人员需要阅读您的代码,而缩进较少的代码通常更容易阅读。

前置条件是一个很好的例子,说明在函数开始时可以提前返回。为什么函数其余部分的可读性会受到前置条件检查的影响?

至于从一个方法返回多次的缺点——现在调试器非常强大,很容易找到特定函数返回的确切位置和时间。

函数中有多个返回值并不会影响维护程序员的工作。

糟糕的代码可读性会。

方法中间的返回并不一定是坏的。如果能使代码的意图更清晰,那么立即返回可能会更好。例如:

double getPayAmount() {
    double result;
    if (_isDead) result = deadAmount();
    else {
        if (_isSeparated) result = separatedAmount();
        else {
            if (_isRetired) result = retiredAmount();
            else result = normalPayAmount();
        };
    }
     return result;
};

在这种情况下,如果_isDead为真,我们可以立即退出该方法。也许这样结构会更好:

double getPayAmount() {
    if (_isDead)      return deadAmount();
    if (_isSeparated) return separatedAmount();
    if (_isRetired)   return retiredAmount();

    return normalPayAmount();
};   

我从重构目录中挑选了这段代码。这种特殊的重构被称为:用保护子句替换嵌套条件句。

我不确定,但我认为,r#试图避免远跳。当你有IF-ELSE时,编译器会做这样的事情:

条件false ->远跳到false_condition_label

true_condition_label: instruction1 ... instruction_n

false_condition_label: instruction1 ... instruction_n

结束块

如果condition为真,则没有跳转,也没有L1缓存的滚出,但是跳转到false_condition_label可能很远,处理器必须滚出自己的缓存。同步缓存的开销很大。r#尝试将远跳转替换为短跳转,在这种情况下有更大的概率,所有指令都已经在缓存中。