18

在最近使用 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?

4

10 回答 10

31

作为一项规则,我发现最好始终以任何条件启动语句块,因为它会降低复杂性,但更重要的是在它们进一步执行之前抛出不兼容的情况,这可以提高代码和内存性能。这还可以通过维护确保您的条件在一段时间内的安全性,从而不太可能将无效场景传递到它们不属于的代码中。

另外,我认为两者中的第二个个人更具可读性,因为您没有范围层混淆可用的内容,很容易在以后的一层中创建一个变量,而没有意识到它在另一层中不可用,或者不得不管理它们以进行适当的修改等。

这不仅仅是在循环中继续,而是指方法的条件应该返回;而不是有一个方法开始

if (valid)
{
    do stuff;
}

它应该总是开始

if (notValid)
{
    return;
}
于 2010-07-26T19:18:06.530 回答
8

应该没有显着的性能差异,这都是关于可读性的。我个人认为后者更容易阅读。嵌套更少,更易于阅读。

于 2010-07-26T19:16:16.173 回答
6

简短的回答:

我倾向于使用缩进,这样它意味着发生了一些真正的决策逻辑,即。预期不止一个可能的执行路径的逻辑。

更长的答案:

通常更喜欢缩进块而不是前面的“中断”语句(、、、continue或)。breakreturnthrow

原因:在我看来,中断语句通常会使代码更难阅读。如果您缩进代码,很容易找到某些决策逻辑发生的位置:这将是缩进较少的代码的第一行。如果您使用带倒置条件的中断语句,您必须做更多的工作来了解代码如何分支以及在哪些情况下跳过某些代码。

对我来说有一个值得注意的例外,即在方法的开头验证参数。我将此代码格式化如下:

if (thisArgument == null) throw new NullArgumentException("thisArgument");
if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument");
...

原因:由于我不期望这些异常实际上被抛出(即我期望方法被正确调用;调用函数负责检测无效输入,IMO),我不想缩进所有其余部分不应该发生的事情的代码。

于 2010-07-26T19:38:20.937 回答
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()的 s 来调用每个重构的方法,并且我会保留嵌套结构。

于 2010-07-26T19:18:02.483 回答
2

简单的回答。哪一个更容易阅读和理解。

于 2010-07-26T19:16:24.140 回答
2

使用两者的组合。我在循环的顶部使用if(condition) continue;and来验证当前状态,并进一步向下嵌套语句来控制我想要完成的任何事情的流程。if(condition) return;if

于 2010-07-26T19:33:57.860 回答
1

在内存或性能方面没有区别。底层 IL 只是分支/跳转指令的选择,因此它们是跳转回循环顶部还是跳转到“else”语句并不重要。

你应该选择更容易阅读的那个。我个人更喜欢避免“继续”,但如果你有很多层次的嵌套,那么你的第二个例子会更容易理解。

于 2010-07-26T19:18:36.763 回答
1

使用continues 使大部分代码处于常规过程代码的级别。否则,如果有五次检查,您将根据缩进大小将方法的“肉”缩进 10 或 20 个字符,而这些是 10/20 字符,您必须滚动才能看到较长的行。

于 2010-07-26T19:19:09.617 回答
1

本义continue:当任何条件为假时,代码不会被处理。下面是一个例子:

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

输出将是: 在此处输入图像描述

于 2014-03-29T09:40:01.423 回答
0

但是从我的开发背景来看,在阅读代码时,前面的示例更容易理解。

嗯 - 我认为,这是你的个人意见。我 - 例如 - 尽量避免这种嵌套,因为在我看来它会使代码更难阅读。

如果您更喜欢“之前”版本而不是“之后”版本,请使用它。
只需配置 ReSharper,让它建议真正想要的。

永远记住:ReSharper 是一个相当“愚蠢”的重构工具——它不能取代开发人员。它只能通过做一些其他愚蠢的复制和粘贴工作来帮助他。
即使在 ReSharper 建议相反的重构的情况下,ReSharper 完成的一些重构也会产生结果。

因此,不要将 ReSharper 的建议视为最佳实践,而是您可以做的可能性。

顺便说一句:您应该在这里考虑性能 - 如果性能确实存在显着差异,我会感到惊讶。

于 2010-07-26T19:18:33.060 回答