如何在开关区内摆脱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;
}
}
答案 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"
系列语句,以便break
从foreach()
循环退出。