通过在循环中使用continue来避免嵌套

本文关键字:continue 嵌套 循环 | 更新日期: 2023-09-27 18:29:59

当我们有一个循环(无论是whilefor等),并且其中有一个简单的条件,指定当前循环是否应该完成任何工作(这样做将产生进一步的嵌套缩进)时,可以简单地测试这个条件的否定并调用continue来忽略循环中的当前元素(从而避免嵌套结构)吗?

或者有什么理由不使用continue

例如:

foreach (var t in new[] {1, 2, 3})
{
    int n = SomeOperation(t);
    if (n == 1) continue;
    // further stuff
}

与形成对比

foreach (var t in new[] {1, 2, 3})
{
    int n = SomeOperation(t);
    if (n != 1) 
    {
        // further stuff
    }
}

通过在循环中使用continue来避免嵌套

确实没有理由不使用continue,它的存在是有原因的。

尽管这并不是说这是你的例子中最好的方法。想想你想在这里做什么。。。

对集合中的元素子集执行操作

既然如此,确定子集的责任应该属于哪里?手术中?或者,应该在操作之前将该子集选择为其自己独特的代码段吗?我认为,关注点的分离决定了这一点。考虑一下对您的示例的修改:

var collection = new[] {1, 2, 3};
// other code doing other things on the collection here, then...
var filteredCollection = collection.Where(x => x != 1);
foreach (var t in filteredCollection)
    PerformSomeOperation(t);

这样可以使循环更小、更简单。通过将循环的操作提取到一个单独的方法中更是如此。现在循环只做一件事。。。对集合进行迭代。集合的定义及其创建方式完全是一个单独的问题。

continue关键字本身的使用并不是一件坏事。但在这种特殊的情况下,它提供了一个机会,可以退一步询问代码的任何给定部分是否做了太多可以分离的事情。

所以我想你有什么:

foreach (var t in new[] {1, 2, 3}) 
{
    if (t != 1)
    {
       ...
    }
}

与其使用Continue或其他一些不明显的分支,我更喜欢的处理方法是使用linq:过滤源

foreach (var t in new[] {1, 2, 3}.Where(i => i != 1))
{
    ...
}

这是可以的。但在某些情况下,这段代码会更好:

foreach (var t in new[] {1, 2, 3}.Where(c=>c!=1))
{
    // further stuff which would be nested if we´d not use continue (negating the condition)
}

在下一步中,您可以用另一种方法封装您的工人:

public void PerformAction(int element)
{
     // further stuff which would be nested if we´d not use continue (negating the condition)
}

并使用Monads的monad-Do for.net:

var collection = new[] {1, 2, 3};
var processedCollection = collection.Where(c => c != 1).Do(PerformAction);

像这样的守护者声明可能是一种气味,您应该提前过滤集合。这在很大程度上取决于您的域、您需要该条件的原因以及您的代码和工作流如何继续。我认为这个问题没有一般的答案。