80 votes

Sortir d'une boucle foreach à l'intérieur d'un bloc switch

Comment sortir d'une boucle foreach à l'intérieur d'un bloc switch ?

Normalement, vous utilisez break mais si vous utilisez un break à l'intérieur d'un bloc switch, cela vous fera juste sortir d'un bloc switch et la boucle foreach continuera son exécution :

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

Ce que je fais actuellement quand j'ai besoin de sortir de la foreach alors qu'au sein de la switch fixe un bool placée à l'extérieur de la boucle à true et en vérifiant la valeur de ce bool à chaque fois que la fonction foreach et avant d'entrer dans le bloc de commutation. Quelque chose comme ça :

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

Cela fonctionne mais je continue à penser qu'il doit y avoir une meilleure façon de faire que je ne connais pas...

EDIT : Je me demande pourquoi cela n'a pas été implémenté dans .NET de la manière très soignée dont cela fonctionne dans PHP comme mentionné par @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;
    }
}

0 votes

Je ne sais pas s'il existe une meilleure solution, mais ce serait comme si on devait sortir d'une boucle extérieure tout en restant dans la boucle intérieure. Jusqu'à présent, je n'ai pas trouvé de moyen de le faire et donc l'utilisation d'une valeur de drapeau semble être la seule solution.

0 votes

0 votes

Plus de 15 ans d'expérience me disent que parfois goto est la meilleure option, rapide et optimisée, garder l'algorithme dans un petit endroit : le garder rapide, efficace, atomique, sans le détruire en mille morceaux, réduire les appels inutiles. Exemples, analyse des ondes acoustiques, vision artificielle, temps réel, etc. Un drapeau ne le rendra pas plus lent, je le vois comme impossible, mais beaucoup de drapeaux peuvent être un problème de lecture.

83voto

Reed Copsey Points 315315

Votre solution est à peu près l'option la plus courante dans ce cas. Ceci étant dit, je mettrais votre contrôle de sortie à la fin :

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

L'autre option principale est de remanier votre code, et de retirer l'instruction switch et la boucle foreach dans une méthode distincte. Vous pourriez alors simplement return de l'intérieur de l'énoncé du commutateur.

28voto

siride Points 36602

Le booléen est un moyen. Une autre est l'utilisation d'étiquettes et de goto. Je sais que les gens considèrent le goto comme un péché capital, mais utilisé judicieusement (TRÈS judicieusement), il peut être utile. Dans ce cas, placez une étiquette juste après la fin de la boucle foreach. Lorsque vous voulez sortir de la boucle, il suffit d'aller à cette étiquette. Par exemple :

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 : certaines personnes ont mentionné le fait de sortir la boucle dans une méthode séparée afin de pouvoir utiliser return. Je vois l'avantage de cette solution car elle ne nécessite pas de goto et simplifie également la fonction originale qui contient la boucle. Cependant, si la boucle est simple et constitue l'objectif principal de la fonction qui la contient, ou si la boucle utilise des variables out ou ref, alors il est probablement préférable de la laisser en place et d'utiliser goto. En fait, comme le goto et l'étiquette se démarquent, cela rend probablement le code plus clair plutôt que plus lourd. Le mettre dans une fonction séparée pourrait rendre le code simple plus difficile à lire.

6 votes

N'utilisez pas goto. Cela rend le code plus compliqué. La méthode d'extraction est bien meilleure.

10 votes

Il serait préférable que vous déclariez pourquoi Le goto rend le code plus compliqué, surtout lorsque l'alternative est tout aussi compliquée et éloigne le code de son contexte original.

0 votes

L'ajout de fonctions supplémentaires ne rend jamais la lecture du code plus difficile si vos fonctions sont courtes et si leur nom est clair.

17voto

Andrew Bezzub Points 8794

Vous pourriez extraire votre cycle foreach vers la méthode séparée et utiliser return déclaration. Ou vous pourriez faire comme ceci :

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

13voto

meagar Points 85475

Honnêtement ? C'est peut-être la seule situation où il est tout à fait valable et correct d'utiliser 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

2 votes

Pourquoi utiliser goto ? C'est bien mieux d'extraire la méthode. Chaque fois que vous utilisez l'instruction goto, un chaton meurt.

5 votes

Pourquoi extraire une méthode quand on peut simplement faire un goto ? C'est six dans l'un, une demi-douzaine dans l'autre, vraiment. Si la boucle est suffisamment petite pour appartenir à une seule fonction en premier lieu, il semble un peu étrange de la remanier uniquement pour éviter un goto propre et clair.

0 votes

Parce que l'utilisation de goto est douloureuse. Vos méthodes doivent être aussi courtes que possible. Et si elles le sont, vous n'aurez jamais besoin de l'instruction goto.

5voto

Il y a toujours la possibilité de restructurer votre code de façon à ce que vous puissiez return de la switch déclaration.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X