[英]Breaking out of a foreach loop from within a switch block
如何在 switch 塊內跳出 foreach 循環?
通常,你使用 break 但如果你在 switch 塊中使用 break 它只會讓你離開 switch 塊並且 foreach 循環將繼續執行:
foreach (var v in myCollection)
{
switch (v.id)
{
case 1:
if (true)
{
break;
}
break;
case 2;
break
}
}
當我需要在switch
塊內中斷foreach
時,我目前正在做的是將放置在循環外部的bool
值設置為 true 並在每次輸入foreach
和進入 switch 之前檢查此 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 中實現,就像@jon_darkstar 提到的那樣,它在PHP中的工作方式非常簡潔?
$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;
}
}
在這種情況下,您的解決方案幾乎是最常見的選擇。 話雖如此,我會把你的退出檢查放在最后:
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
。
布爾值是一種方式。 另一個是使用標簽和轉到。 我知道人們認為 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
編輯:有些人提到將循環放入單獨的方法中,以便您可以使用返回。 我看到了這樣做的好處,因為它不需要 goto 並且它還簡化了包含循環的原始函數。 但是,如果循環很簡單並且是包含它的函數的主要目的,或者如果循環使用 out 或 ref 變量,那么最好將其留在原處並使用 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;
}
總是可以選擇重構您的代碼,以便您可以從switch
語句中return
。
根據有關break
語句的MSDN 文檔,它只允許停止最頂層的作用域。
在這種情況下,您可以使用goto
語句離開foreach
循環。 如果您不想使用goto
語句,那么您的解決方案似乎是最好的解決方案。
作為旁注,您可以通過在迭代結束時測試exitLoop
標志來改進代碼,從而節省一次枚舉器調用的成本。
跛腳,我知道,但這就是你能做的。
您始終可以將其轉換為 while 循環並添加 'exitLoop' 作為必須滿足的條件。 在 switch 中,你可以調用 continue 跳過當前傳遞的其余部分,因為你將 exitLoop 設置為 false,它會像 break 一樣退出。 即使這不完全是你要問的,也許那樣更優雅?
某些語言(我知道PHP是其中之一,不確定其他語言)允許您指定要突破的控制結構數量
打破 n;
如果您只是中斷,則隱含 1
break 2 會做你所描述的,如果它在 C# 中可用。 我不相信是這樣,所以你的退出標志可能是最好的解決方案。
另一種方法是使用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");
您可以使用 Try/Catch 來實現。但它可能不是世界上最好的主意,因為它會導致性能問題並且確實會在調試窗口中顯示令人討厭的行。
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"
系列語句,以便break
從foreach()
循環中退出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.