Breaking out of a foreach loop from within a switch block

C#.Net

C# Problem Overview


How do you break out of a foreach loop while within a switch block?

Normally, you use break but if you use a break within a switch block it will just get you out of a switch block and the foreach loop will continue execution:

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

What I'm currently doing when I need to break out of the foreach while within the switch block is setting a bool value placed outside of the loop to true and checking the value of this bool every time the foreach is entered and before entering the switch block. Something like this:

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

This works but I keep thinking there must be a better way of doing this I am unaware of...

EDIT: Wonder why this was not implemented in .NET the really neat way it works in PHP as mentioned by @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;
    }
}

C# Solutions


Solution 1 - C#

Your solution is pretty much the most common option in this case. That being said, I'd put your exit check at the end:

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

The other main option is to refactor your code, and pull the switch statement and foreach loop out into a separate method. You could then just return from inside the switch statement.

Solution 2 - C#

The boolean is one way. Another is using labels and goto. I know folks consider goto to be a cardinal sin, but used judiciously (VERY judiciously), it can be useful. In this case, place a label just past the end of the foreach loop. When you want to exit the loop, simply goto that label. For example:

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

EDIT: some people have mentioned taking the loop out into a separate method so that you can use return. I see the benefit of this as it doesn't require goto and it also simplifies the original function that contained the loop. However, if the loop is simple and is the primary purpose of the function that contains it, or if the loop makes use of out or ref variables, then it's probably best to just leave it in place and use the goto. In fact, because the goto and the label stand out, it probably makes the code clearer rather than clunkier. Putting it in a separate function could make simple code harder to read.

Solution 3 - C#

You could extract your foreach cycle to the separate method and use return statement. Or you could do like this:

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

Solution 4 - C#

Honestly? This is perhaps the only situation where it is completely valid and proper to use 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

Solution 5 - C#

It's not really different from your exitLoop flag, but it might be more readable if you extract a method...

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

Solution 6 - C#

There's always the option of restructuring your code so that you can return from the switch statement.

Solution 7 - C#

Based on MSDN documentation on the break statement, it only allows to stop the top-most scope.

This case is one where you could use a goto statement to leave your foreach loop. If you don't want to use a goto statement, your solution seems to be the best one.

As a side note, you could improve your code by testing the exitLoop flag at the end of the iteration, saving the cost of one enumerator call.

Solution 8 - C#

Lame, I know, but that's all you can do about it.

You could always transform it into a while loop and add 'exitLoop' as a condition which must be met. Inside the switch, you can call continue to skip the rest of the current pass and since you would have set exitLoop to false, it'd exit much like break would do. Even though it's not exactly what you're asking, perhaps it's more elegant that way?

Solution 9 - C#

Some languages (i know http://php.net/manual/en/control-structures.break.php">PHP</a> is one, not sure about others) allow you to specify how many control structures you'd like to break out of with

break n;
where 1 is implied if you just do break

break 2 would do what you describe, were it available in C#. I don't believe that's the case so your exit flag is probably the best solution.

Solution 10 - C#

Another way to do that is using goto, but extracting to a method would be preferable

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");

Solution 11 - C#

You can do it with Try/Catch.. But it might not be the best idea in the world, because it causes performance problems and does show nasty lines in the debug window.

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

Solution 12 - C#

Transform the switch() statement into a "if() else if() [...] else" series of statements so that the break exits from the foreach() loop.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDean KugaView Question on Stackoverflow
Solution 1 - C#Reed CopseyView Answer on Stackoverflow
Solution 2 - C#sirideView Answer on Stackoverflow
Solution 3 - C#Andrew BezzubView Answer on Stackoverflow
Solution 4 - C#user229044View Answer on Stackoverflow
Solution 5 - C#dahlbykView Answer on Stackoverflow
Solution 6 - C#Klaus Byskov PedersenView Answer on Stackoverflow
Solution 7 - C#Thibault FaliseView Answer on Stackoverflow
Solution 8 - C#NeilView Answer on Stackoverflow
Solution 9 - C#jon_darkstarView Answer on Stackoverflow
Solution 10 - C#Davi FiamenghiView Answer on Stackoverflow
Solution 11 - C#One ideaView Answer on Stackoverflow
Solution 12 - C#SenbeiView Answer on Stackoverflow