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

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

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

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

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


当前回答

这完全是有争议的。在提前返回的问题上,“程序员之间没有达成一致”。据我所知,这总是主观的。

这是有可能的,因为最好有条件,所以它们通常是真的;也可以说,它更清晰。另一方面,它确实创建了嵌套测试。

我不认为你会对这个问题得到一个结论性的答案。

其他回答

关于代码的外观有很多很好的理由。但是结果如何呢?

让我们来看看一些c#代码和它的IL编译形式:

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length == 0) return;
        if ((args.Length+2)/3 == 5) return;
        Console.WriteLine("hey!!!");
    }
}

可以编译这个简单的代码片段。您可以使用ildasm打开生成的.exe文件并检查结果。我不会发布所有汇编程序的东西,但我会描述结果。

生成的IL代码执行以下操作:

如果第一个条件为假,则跳转到第二个条件所在的代码。 如果为真,则跳转到最后一条指令。(注意:最后一个指令是return)。 在第二种情况下,计算结果后也会发生同样的情况。比较和:到达控制台。如果为假则写eline,如果为真则写到结尾。 打印消息并返回。

所以看起来代码会跳到最后。如果我们对嵌套代码做一个正常的if呢?

using System;

public class Test {
    public static void Main(string[] args) {
        if (args.Length != 0 && (args.Length+2)/3 != 5) 
        {
            Console.WriteLine("hey!!!");
        }
    }
}

结果在IL指令中非常相似。不同之处在于,之前每个条件有两次跳转:如果为假则跳转到下一段代码,如果为真则跳转到最后一段代码。现在IL代码流得更好了,有3个跳跃(编译器优化了一点):

第一次跳转:当Length为0到代码再次跳转(第三次跳转)的部分时。 第二:在第二种情况中间避免一条指令。 第三:如果第二个条件为假,跳到最后。

不管怎样,程序计数器总是会跳转。

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

它不仅美观,而且还减少了方法内部的最大嵌套级别。这通常被认为是一个优点,因为它使方法更容易理解(事实上,许多静态分析工具提供了一种度量方法,作为代码质量的指标之一)。

另一方面,它还使您的方法具有多个退出点,另一组人认为这是不可取的。

就我个人而言,我同意ReSharper和第一组(在有例外的语言中,我发现讨论“多个退出点”是愚蠢的;几乎任何东西都可能抛出,所以在所有方法中都有许多潜在的退出点)。

关于性能:每种语言的两个版本都应该是等效的(如果不是在IL级别,那么肯定是在代码抖动结束后)。从理论上讲,这取决于编译器,但实际上,今天任何广泛使用的编译器都能够处理比这更高级的代码优化情况。

这完全是有争议的。在提前返回的问题上,“程序员之间没有达成一致”。据我所知,这总是主观的。

这是有可能的,因为最好有条件,所以它们通常是真的;也可以说,它更清晰。另一方面,它确实创建了嵌套测试。

我不认为你会对这个问题得到一个结论性的答案。

我想这要看你喜欢什么了,如前所述,没有统一的意见。 为了减少麻烦,您可以将这种警告减少为“提示”。