从一个开关块中分解出一个foreach循环

如何在开关块内跳出foreach循环?

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

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

我现在要做的就是在switch块内部需要跳出foreach时候,把循环外部的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; } } 

在这种情况下,您的解决scheme几乎是最常见的select。 这就是说,我会把你的退出检查结束:

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

另一个主要的select是重构你的代码,并把switch语句和foreach循环放到一个单独的方法中。 然后你可以从switch语句中return

布尔是一种方式。 另一个是使用标签和转到。 我知道人们认为是基本的罪过,但明智地使用(非常明智),它可能是有用的。 在这种情况下,将标签放在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 

编辑:有人已经提到把这个循环带到一个单独的方法,以便您可以使用返回。 我看到这个好处,因为它不需要转到,它也简化了包含循环的原始函数。 但是,如果循环是简单的并且是包含它的函数的主要目的,或者如果循环使用out或refvariables,那么最好放置它并使用goto。 实际上,由于goto和标签脱颖而出,可能会使代码更清晰而不是笨拙。 把它放在一个单独的函数可以使简单的代码难以阅读。

你可以提取你的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. } } 

说实话? 这也许是使用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 

它与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; } 

总是可以select重构代码,以便从switch语句return

基于break语句上的MSDN文档 ,它只允许停止最上面的范围。

这种情况下,你可以使用goto语句离开你的foreach循环。 如果你不想使用goto语句,你的解决scheme似乎是最好的。

作为一个方面说明,你可以通过在迭代结束时testingexitLoop标志来改善你的代码,节省一个枚举器调用的代价。

瘸腿,我知道,但这就是你所能做的。

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

一些语言(我知道PHP是一个,不知道其他人)允许你指定有多less控制结构你想摆脱

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

break 2会做你所描述的,如果它在C#中可用的话。 我不相信是这样,所以你的出口标志可能是最好的解决scheme。

你可以用Try / Catch来做。但是它可能不是世界上最好的想法,因为它会导致性能问题,并且在debugging窗口中显示不好的行。

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

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