从开关块中断开foreach循环

时间:2010-10-28 16:02:17

标签: c# .net

如何在开关区内摆脱foreach循环?

通常情况下,你使用break但如果在switch块中使用break,它只会让你离开switch块而foreach循环将继续执行:

foreach (var v in myCollection)
{
    switch (v.id)
    {
        case 1:
            if (true)
            {
                break;
            }
            break;
        case 2;
            break
    }
}

当我需要在foreach块内突破switch时,我正在做的是将位于循环外的bool值设置为true并检查每次输入foreach时和进入开关块之前,此bool的值。像这样:

bool exitLoop;
foreach (var v in myCollection)
{
    if (exitLoop) break;
    switch (v.id)
    {
        case 1:
            if (true)
            {
                exitLoop = true;
                break;
            }
            break;
        case 2;
            break
    }
}

这有效,但我一直认为必须有一个更好的方法,我不知道......

编辑:想知道为什么在.NET中没有实现它在PHP中工作的非常简洁的方式,正如@jon_darkstar所提到的那样?

$i = 0;
while (++$i) {
    switch ($i) {
    case 5:
        echo "At 5<br />\n";
        break 1;  /* Exit only the switch. */
    case 10:
        echo "At 10; quitting<br />\n";
        break 2;  /* Exit the switch and the while. */
    default:
        break;
    }
}

12 个答案:

答案 0 :(得分:57)

在这种情况下,您的解决方案几乎是最常见的选择。话虽这么说,我会在最后进行退出检查:

bool exitLoop;
foreach (var v in myCollection)
{
    switch (v.id)
    {
        case 1:
            if (true)
            {
                exitLoop = true;
            }
            break;
        case 2;
            break
    }

    // This saves an iteration of the foreach...
    if (exitLoop) break;
}

另一个主要选项是重构代码,并将switch语句和foreach循环拉出到单独的方法中。然后,您可以从switch语句中单独return

答案 1 :(得分:24)

布尔值是单向的。另一个是使用标签和转到。我知道人们认为goto是一个主要的罪恶,但明智地使用(非常明智地),它可能是有用的。在这种情况下,将标签放在foreach循环的末尾。如果要退出循环,只需转到该标签即可。例如:

foreach(var v in myCollection) {
    switch(v.Id) {
        case 1:
            if(true) {
                goto end_foreach;
            }
            break;
        case 2:
            break;
    }
}
end_foreach:
// ... code after the loop
编辑:有些人提到将循环带入一个单独的方法,以便您可以使用return。我看到了这个的好处,因为它不需要goto,它还简化了包含循环的原始函数。但是,如果循环很简单并且是包含它的函数的主要目的,或者循环使用out或ref变量,那么最好将其保留到位并使用goto。事实上,因为goto和标签脱颖而出,它可能使代码更清晰而不是笨拙。将它放在一个单独的函数中可能会使简单的代码更难阅读。

答案 2 :(得分:16)

您可以将foreach循环提取到单独的方法并使用return语句。或者你可以这样做:

        foreach (object collectionElement in myCollection)
        {
            if (ProcessElementAndDetermineIfStop(collectionElement))
            {
                break;
            }
        }

        private bool ProcessElementAndDetermineIfStop(object collectionElement)
        {
            switch (v.id)
            {
                case 1:
                    return true; // break cycle.
                case 2;
                    return false; // do not break cycle.
            }
        }

答案 3 :(得分:10)

诚实?这可能是使用goto完全有效和正确的唯一情况:

foreach (var v in myCollection) {
    switch (v.id) {
        case 1:
            if (true)
                // document why we're using goto
                goto finished;
            break;
        case 2;
            break
    }
}
finished: // document why I'm here

答案 4 :(得分:6)

它与您的exitLoop标志没有什么不同,但如果您提取方法,它可能更具可读性......

foreach (var v in myCollection)
{
    if(!DoStuffAndContinue(v))
        break;
}


bool DoStuffAndContinue(MyType v)
{
    switch (v.id)
    {
        case 1:
            if (ShouldBreakOutOfLoop(v))
            {
                return false;
            }
            break;
        case 2;
            break;
    }
    return true;
}

答案 5 :(得分:5)

总是可以选择重构代码,以便return语句switch {/ 1}}。

答案 6 :(得分:2)

基于break语句中的MSDN documentation,它只允许停止最高范围。

在这种情况下,您可以使用goto语句离开foreach循环。 如果您不想使用goto语句,那么您的解决方案似乎是最好的解决方案。

作为旁注,您可以通过在迭代结束时测试exitLoop标志来改进代码,从而节省一个枚举器调用的成本。

答案 7 :(得分:1)

Lame,我知道,但这就是你能做的一切。

您总是可以将其转换为while循环,并添加'exitLoop'作为必须满足的条件。在交换机内部,你可以调用continue继续跳过当前传递的其余部分,因为你将exitLoop设置为false,它会像break那样退出。即使它不是你所要求的,也许这样更优雅?

答案 8 :(得分:1)

有些语言(我知道PHP是一个,不确定其他语言)允许你指定你想要打破多少控制结构

打破n;
如果你只是打破了,那么暗示1是

break 2会按照你描述的方式进行,如果它在C#中可用。我不相信这种情况,所以你的退出标志可能是最好的解决方案。

答案 9 :(得分:0)

使用goto

int[] numbers = { 1, 2, 3, 4, 5 };
foreach (var number in numbers)
{
    switch (number)
    {
        case 1:
            break;
        case 2:
            goto breakLoop;
        default:
            break;
    }

}
breakLoop:
Console.Write("Out of loop");

答案 10 :(得分:-1)

你可以用Try / Catch来做到这一点。 但它可能不是世界上最好的主意,因为它会导致性能问题并且在调试窗口中显示出令人讨厌的行。

try
{ 
foreach (var v in myCollection)
    {
        switch (v.id)
        {
            case 1:
                if (true)
                {
                    throw new SystemException("Break");
                }
                break;
            case 2;
                break;
        }
    }
} catch {}

答案 11 :(得分:-2)

将switch()语句转换为"if() else if() [...] else"系列语句,以便breakforeach()循环退出。