簡體   English   中英

從 switch 塊中跳出 foreach 循環

[英]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"系列語句,以便breakforeach()循環中退出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM