Een foreach-lus doorbreken vanuit een schakelblok

Hoe doorbreek je een foreach-lus binnen een schakelblok?

Normaal gesproken gebruik je pauze, maar als je een pauze binnen een schakelblok gebruikt, kom je gewoon uit een schakelblok en gaat de foreach-lus verder met de uitvoering:

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

Wat ik momenteel aan het doen ben wanneer ik uit de foreachmoet ontsnappen terwijl binnen het switch-blok een bool-waarde wordt geplaatst buiten de lus naar waar en de waarde van deze bool controleren elke keer dat de foreachwordt ingevoerd en voordat het schakelblok wordt ingevoerd. Zoiets als dit:

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

Dit werkt, maar ik blijf denken dat er een betere manier moet zijn om dit te doen waar ik niet van op de hoogte ben…

EDIT: Vraag me af waarom dit niet is geïmplementeerd in .NET zoals het werkt in PHPzoals vermeld door @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;
    }
}

Antwoord 1, autoriteit 100%

Uw oplossing is in dit geval vrijwel de meest gebruikelijke optie. Dat gezegd hebbende, zou ik je exit check aan het einde zetten:

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

De andere hoofdoptie is om uw code te refactoren en de switch-instructie en foreach-lus naar een afzonderlijke methode te trekken. U kunt dan gewoon returnvanuit de switch-instructie.


Antwoord 2, autoriteit 38%

De boolean is eenrichtingsverkeer. Een andere is het gebruik van labels en goto. Ik weet dat mensen goto als een doodzonde beschouwen, maar als het oordeelkundig (ZEER oordeelkundig) wordt gebruikt, kan het nuttig zijn. Plaats in dit geval een label net voorbij het einde van de foreach-lus. Als u de lus wilt verlaten, gaat u gewoon naar dat label. Bijvoorbeeld:

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: sommige mensen hebben gezegd om de lus naar een aparte methode te brengen, zodat je return kunt gebruiken. Ik zie het voordeel hiervan in omdat het geen goto vereist en het vereenvoudigt ook de originele functie die de lus bevatte. Als de lus echter eenvoudig is en het primaire doel is van de functie die deze bevat, of als de lus gebruikmaakt van out- of ref-variabelen, dan is het waarschijnlijk het beste om hem gewoon op zijn plaats te laten en de goto te gebruiken. In feite, omdat de goto en het label opvallen, maakt het de code waarschijnlijk duidelijkerin plaats van onhandiger. Door het in een aparte functie te plaatsen, kan eenvoudige code moeilijker te lezen zijn.


Antwoord 3, autoriteit 23%

U kunt uw foreach-cyclus extraheren naar de afzonderlijke methode en de instructie returngebruiken. Of je zou het als volgt kunnen doen:

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

Antwoord 4, autoriteit 18%

Eerlijk gezegd? Dit is misschien de enige situatie waarin het volledig geldig en juist is om 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

Antwoord 5, autoriteit 11%

Het verschilt niet echt van uw exitLoop-vlag, maar het is misschien beter leesbaar als u een methode extraheert…

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

Antwoord 6, autoriteit 7%

Er is altijd de mogelijkheid om je code te herstructureren, zodat je returnvan de switch-instructie.


Antwoord 7, autoriteit 3%

Gebaseerd op MSDN-documentatieop de break-instructie, kan alleen het bovenste bereik worden gestopt.

In dit geval zou je een goto-statement kunnen gebruiken om je foreach-lus te verlaten.
Als u geen goto-statement wilt gebruiken, lijkt uw oplossing de beste.

Als een kanttekening: u kunt uw code verbeteren door de vlag exitLoopaan het einde van de iteratie te testen, waardoor u de kosten van één enumerator-aanroep bespaart.


Antwoord 8

Kreupel, ik weet het, maar dat is alles wat je eraan kunt doen.

Je zou het altijd kunnen omzetten in een while-lus en ‘exitLoop’ toevoegen als een voorwaarde waaraan moet worden voldaan. Binnen de switch kun je blijven bellen om de rest van de huidige pas over te slaan en aangezien je exitLoop op false zou hebben ingesteld, zou het afsluiten net zoals pauze zou doen. Ook al is het niet precies wat je vraagt, misschien is het op die manier eleganter?


Antwoord 9

Sommige talen (ik weet dat PHPer een is, ik weet het niet zeker anderen) kunt u specificeren met hoeveel controlestructuren u wilt breken met

breek n;
waarbij 1 wordt geïmpliceerd als je gewoon breekt

break 2 zou doen wat je beschrijft, als het beschikbaar was in C#. Ik geloof niet dat dat het geval is, dus je exit-vlag is waarschijnlijk de beste oplossing.


Antwoord 10

Een andere manier om dat te doen is met behulp van goto, maar extraheren naar een methode heeft de voorkeur

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

Other episodes