最近使用ReSharper时,建议我通过反转if
条件并使用continue
语句来减少某些地方的嵌套。
嵌套条件:
foreach(....)
{
if(SomeCondition)
{
//do some things
if(SomeOtherNestedCondition)
{
//do some further things
}
}
}
继续声明:
foreach(....)
{
if(!SomeCondition) continue;
//do some things
if(!SomeOtherNestedCondition) continue;
//do some further things
}
我理解为什么你想减少嵌套的性能和内存问题以及两个片段如何相互等同的一些逻辑,但是从我的开发背景,之前在阅读代码时,示例更容易理解。
您更喜欢哪种方法?为什么?您是否在日常代码中使用continue
而不是嵌套ifs?
答案 0 :(得分:29)
作为一项规则,我发现总是最好始终使用除了out之外的任何条件启动语句块,因为它会降低复杂性,但更重要的是在它们被进一步推进之前抛出不兼容的情况,这会增加代码和内存性能。这也通过维护确保您的条件在一段时间内的安全性,并且不太可能将无效的方案传递到他们不属于的代码中。
另外我认为两者中的第二个更具可读性,因为你没有让范围层混淆可用的东西,很容易在后面的一层中创建变量并且没有意识到它在另一层中不可用,或者必须管理它们以进行适当的修改等。
这不仅仅是循环中的继续,而且这也是指应该返回的方法条件;而不是让方法开始
if (valid)
{
do stuff;
}
它应该始终开始
if (notValid)
{
return;
}
答案 1 :(得分:8)
应该没有显着的性能差异,这完全取决于可读性。我个人认为后者更容易阅读。减少嵌套,更易于阅读。
答案 2 :(得分:6)
我倾向于使用缩进,这意味着发生了一些真正的决策逻辑,即。逻辑中需要多个可能的执行路径。
我通常更喜欢缩进块到前面的“破解”语句(continue
,break
,return
或throw
)。
原因:在我看来,破坏语句通常会使代码难以阅读。如果你缩进代码,很容易找到一些决策逻辑发生的位置:这将是缩小代码的第一行。如果你使用具有反转条件的break语句,你必须做更多的工作来理解代码如何分支以及在什么情况下跳过某些代码。
对我来说有一个值得注意的例外,即在方法开头验证参数。我将此代码格式化如下:
if (thisArgument == null) throw new NullArgumentException("thisArgument");
if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument");
...
原因:因为我不希望实际抛出这些异常(也就是说,我希望正确调用该方法;调用函数负责检测无效输入,IMO),我不想将所有其他代码缩进到不应该发生的事情。
答案 3 :(得分:4)
使用continue
样式代码;你将如何处理不依赖于SomeOtherNestedCondition的第三个操作,这使得代码的顺序变得很重要,IMO使其不易维护。
例如:
foreach(....)
{
if(!SomeCondition) continue;
//do some things
if(!SomeOtherNestedCondition) continue;
//do some further things
if(!SomeSecondNonNestedCondition) continue;
// do more stuff
}
当SomeOtherNestedCondition导致continue;
发生时会发生什么,但SomeSecondNonNestedCondition仍应执行?
我会重构每一段“代码”并使用嵌套的if()
来调用每个重构的方法,并且我会保留嵌套的结构。
答案 4 :(得分:2)
简单的回答。哪一个更容易阅读和理解。
答案 5 :(得分:2)
使用两者的组合。我在循环顶部使用if(condition) continue;
和if(condition) return;
来验证当前状态,并进一步嵌套if
语句来控制我想要完成的任何事情的流程。
答案 6 :(得分:1)
内存或性能方面没有区别。底层的IL只是一个分支/跳转指令的选择,因此它们是否跳回到循环的顶部或“else”语句并不重要。
您应该选择更容易阅读的内容。我个人更喜欢避免'继续',但如果你有很多级别的嵌套,那么你的第二个例子可以更容易理解。
答案 7 :(得分:1)
使用continue
s可以在常规过程代码级别上创建大量代码。
否则,如果有五个检查,您将缩进方法10或20个字符的“肉”,具体取决于缩进大小,这些是10/20字符,您必须滚动以查看较长的行。
答案 8 :(得分:1)
原始continue
含义:在任何条件为false时,代码都不会被处理。以下是一个例子:
class Program
{
static bool SomeCondition = false;
static bool SomeOtherNestedCondition = false;
static void Main(string[] args)
{
for (int i = 0; i < 2; i++)
{
if (SomeCondition)
{
//do some things
if (SomeOtherNestedCondition)
{
//do some further things
}
}
Console.WriteLine("This text appeared from the first loop.");
}
for (int i = 0; i < 2; i++)
{
if (!SomeCondition) continue;
//do some things
if (!SomeOtherNestedCondition) continue;
//do some further things
Console.WriteLine("This text appeared from the second loop.");
}
Console.ReadLine();
}
}
输出将是:
答案 9 :(得分:0)
但是从我的开发背景来看,在阅读代码时,前面的示例更容易理解。
嗯 - 我想,这是你的个人意见。我 - 例如 - 试图避免这样的嵌套,因为它使代码更难以在我看来阅读。
如果您喜欢“之前”版本而不是“之后”版本,请使用它。
只需配置ReSharper,即可建议你真正想要的内容。
始终牢记:ReSharper是一个非常“愚蠢”的重构工具 - 它无法取代开发人员。它只能通过做一些其他愚蠢的复制和粘贴工作来帮助他。
ReSharper完成的一些重构甚至在ReSharper暗示相反重构的情况下也会产生。
因此,不要将ReSharper的建议视为最佳实践,而是将其作为可能性。
顺便说一句:你应该受到性能方面的考虑 - 如果性能上存在显着的差异,我会感到惊讶。