例如,当我在我的代码上运行ReSharper时:
if (some condition)
{
Some code...
}
ReSharper给了我上面的警告(反转“if”语句以减少嵌套),并建议以下更正:
if (!some condition) return;
Some code...
我想知道为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。
例如,当我在我的代码上运行ReSharper时:
if (some condition)
{
Some code...
}
ReSharper给了我上面的警告(反转“if”语句以减少嵌套),并建议以下更正:
if (!some condition) return;
Some code...
我想知道为什么这样更好。我一直认为在方法中间使用“return”是有问题的,有点像“goto”。
当前回答
这完全是有争议的。在提前返回的问题上,“程序员之间没有达成一致”。据我所知,这总是主观的。
这是有可能的,因为最好有条件,所以它们通常是真的;也可以说,它更清晰。另一方面,它确实创建了嵌套测试。
我不认为你会对这个问题得到一个结论性的答案。
其他回答
这是一个有点宗教的争论,但我同意ReSharper的观点,你应该更喜欢少嵌套。我相信这超过了一个函数有多条返回路径的缺点。
减少嵌套的关键原因是为了提高代码的可读性和可维护性。请记住,将来会有许多其他开发人员需要阅读您的代码,而缩进较少的代码通常更容易阅读。
前置条件是一个很好的例子,说明在函数开始时可以提前返回。为什么函数其余部分的可读性会受到前置条件检查的影响?
至于从一个方法返回多次的缺点——现在调试器非常强大,很容易找到特定函数返回的确切位置和时间。
函数中有多个返回值并不会影响维护程序员的工作。
糟糕的代码可读性会。
There are several advantages to this sort of coding but for me the big win is, if you can return quick you can improve the speed of your application. IE I know that because of Precondition X that I can return quickly with an error. This gets rid of the error cases first and reduces the complexity of your code. In a lot of cases because the cpu pipeline can be now be cleaner it can stop pipeline crashes or switches. Secondly if you are in a loop, breaking or returning out quickly can save you a lots of cpu. Some programmers use loop invariants to do this sort of quick exit but in this you can broke your cpu pipeline and even create memory seek problem and mean the the cpu needs to load from outside cache. But basically I think you should do what you intended, that is end the loop or function not create a complex code path just to implement some abstract notion of correct code. If the only tool you have is a hammer then everything looks like a nail.
在我看来,如果你只是返回void(或一些你永远不会检查的无用的返回代码),那么早期返回是很好的,它可能会提高可读性,因为你避免了嵌套,同时你显式地表明你的函数已经完成。
如果你实际上返回一个returnValue,嵌套通常是一个更好的方式,因为你只在一个地方返回你的returnValue(在末尾),它可能会使你的代码在很多情况下更易于维护。
关于代码的外观有很多很好的理由。但是结果如何呢?
让我们来看看一些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到代码再次跳转(第三次跳转)的部分时。 第二:在第二种情况中间避免一条指令。 第三:如果第二个条件为假,跳到最后。
不管怎样,程序计数器总是会跳转。
这里有几个很好的观点,但如果方法非常冗长,多个返回点也可能是不可读的。也就是说,如果你打算使用多个返回点,只要确保你的方法是简短的,否则多个返回点的可读性奖励可能会丢失。