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

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

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

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

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


当前回答

我不确定,但我认为,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#尝试将远跳转替换为短跳转,在这种情况下有更大的概率,所有指令都已经在缓存中。

其他回答

从理论上讲,反转if可以提高分支预测的命中率,从而提高性能。在实践中,我认为很难确切地知道分支预测将如何表现,特别是在编译之后,所以我不会在日常开发中这样做,除非我正在编写汇编代码。

更多关于分支预测的信息。

避免多个退出点可以提高性能。我对c#不太确定,但在c++中,命名返回值优化(复制省略,ISO c++ '03 12.8/15)依赖于有一个单一的出口点。这种优化避免了复制构造返回值(在您的特定示例中,这无关紧要)。在紧密循环中,这可能会大大提高性能,因为每次调用函数时都保存了一个构造函数和一个析构函数。

但是在99%的情况下,节省额外的构造函数和析构函数调用并不值得损失嵌套的可读性,如果块引入(正如其他人所指出的)。

在性能方面,这两种方法之间没有明显的区别。

但是编码不仅仅关乎性能。清晰性和可维护性也非常重要。而且,在这种情况下,它不会影响性能,这是唯一重要的事情。

关于哪种方法更可取,存在着相互竞争的思想流派。

一种观点是其他人已经提到的观点:第二种方法减少了嵌套级别,从而提高了代码的清晰度。这在命令式风格中是很自然的:当你没有什么事情要做的时候,你不妨早点回来。

从函数式风格的角度来看,另一种观点认为一个方法应该只有一个出口点。函数式语言中的一切都是表达式。所以if语句必须总是有一个else子句。否则if表达式并不总是有值。所以在函数式风格中,第一种方法更自然。

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

    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;
    }

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

我不确定,但我认为,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#尝试将远跳转替换为短跳转,在这种情况下有更大的概率,所有指令都已经在缓存中。