2009-07-15 11 views
40

Dans cet exemple de code, existe-t-il un moyen de continuer sur la boucle externe à partir du bloc catch?Continuer dans les boucles imbriquées

while 
{ 
    // outer loop 

    while 
    { 
     // inner loop 
     try 
     { 
      throw; 
     } 
     catch 
     { 
      // how do I continue on the outer loop from here? 
      continue; 
     } 
    } 
} 
+16

Les boucles imbriquées ne mènent qu'au désespoir. –

Répondre

87

MISE À JOUR: Cette question a été une source d'inspiration pour my article on this subject. Merci pour la bonne question! "Continuer" et "break" ne sont rien de plus qu'une syntaxe agréable pour un "goto". Apparemment, en leur donnant des noms mignons et en limitant leurs usages à des structures de contrôle particulières, ils ne sont plus attirés par la colère de la foule «tous les gotos sont tous mauvais tout le temps». Si vous voulez faire un continu à externe, vous pouvez simplement définir une étiquette en haut de la boucle externe et ensuite "goto" cette étiquette. Si vous pensiez que cela ne gênait pas la compréhension du code, alors cela pourrait être la solution la plus opportune.

Cependant, je considérerais ceci comme une opportunité de considérer si votre flux de contrôle bénéficierait d'un refactoring. Chaque fois que j'ai "break" conditionnel et "continuer" dans les boucles imbriquées, je considère refactoring.

Tenir compte:

successfulCandidate = null; 
foreach(var candidate in candidates) 
{ 
    foreach(var criterion in criteria) 
    { 
    if (!candidate.Meets(criterion)) // Edited. 
    { // TODO: no point in continuing checking criteria. 
     // TODO: Somehow "continue" outer loop to check next candidate 
    } 
    } 
    successfulCandidate = candidate; 
    break; 
} 
if (successfulCandidate != null) // do something 

Deux techniques de refactorisation:

D'abord, extraire la boucle interne à une méthode:

foreach(var candidate in candidates) 
{ 
    if (MeetsCriteria(candidate, criteria)) 
    { 
     successfulCandidate = candidate; 
     break; 
    } 
} 

En second lieu, peuvent toutes les boucles éliminés? Si vous faites une boucle parce que vous essayez de chercher quelque chose, refactornez-le en une requête.

var results = from candidate in candidates 
       where criteria.All(criterion=>candidate.Meets(criterion)) 
       select candidate; 
var successfulCandidate = results.FirstOrDefault(); 
if (successfulCandidate != null) 
{ 
    do something with the candidate 
} 

S'il n'y a pas de boucle, il n'est pas nécessaire de rompre ou de continuer!

+5

+1 pour "... extrait la boucle interne d'une méthode". J'ai besoin de beaucoup de justification dans les revues de code lorsque je vois des boucles imbriquées. Ils nuisent généralement à la lisibilité, à la maintenabilité et à la stabilité. La question d'OP peut être résolue avec un simple "retour" ou "lancer" (ne comptant donc pas sur les gotos). –

+6

Absolument. Quand vous pensez avoir besoin d'un «goto», arrêtez-vous un instant et réfléchissez si vous le faites vraiment. Si vous avez toujours besoin d'un 'goto', alors utilisez-le - c'est dans la langue pour une raison. Ce n'est pas intrinsèquement mal non plus - il apparaît généralement dans les modèles diaboliques, et devrait donc servir de signal pour arrêter et essayer de repérer de tels modèles (et de ne pas plonger dans "OMG' goto' c'est tout faux "panique). –

+0

Goto n'est pas intrinsèquement mauvais, mais c'est un médicament de passage au mauvais code paresseux. De tous les moyens de contrôler le débit, c'est * habituellement * le pire. –

10

Swap la structure try/catch avec l'intérieur en boucle:

while { 
    try { 
    while { 
     throw; 
    } 
    } 
    catch { 
    continue; 
    } 
} 
4

n °
Je suggère, l'extraction de la boucle interne dans une méthode distincte.

while 
{ 
    // outer loop 
     try 
     { 
      myMethodWithWhileLoopThatThrowsException() 
     } 
     catch 
     { 
      // how do I continue on the outer loop from here? 
      continue; 
     } 
    } 
} 
+0

Ceci est problématique car la métode séparée n'aura pas accès aux variables locales existantes. – zvrba

+4

C'est pourquoi Microsoft nous a donné des paramètres de fonction. – Welbog

+0

passez les variables en tant que paramètres ou, si des effets de bord sont nécessaires, envoyez-les en tant que délégué anonyme à exécuter dans la méthode. Ensuite, le compilateur va créer une fermeture, en préservant votre portée locale. –

18

Vous pouvez utiliser une coupure; déclaration.

while 
{ 
    while 
    { 
     try 
     { 
      throw; 
     } 
     catch 
     { 
      break; 
     } 
    } 
} 

Continue est utilisé pour revenir au début de la boucle en cours.

Si vous avez besoin de sortir plus de niveaux, vous devrez soit ajouter une sorte de 'si' ou utiliser le 'goto' redouté/non recommandé.

+2

Le problème avec cette méthode est que s'il y a du travail supplémentaire à faire entre la fin de la boucle interne et la fin de la boucle externe, être fait en appelant 'break', mais ne serait pas fait en appelant' continue'. Vous auriez besoin d'un drapeau si vous avez besoin que ce code ne soit pas exécuté. Je ne dis pas que cette réponse est fausse (diable, je l'ai upvoted), je dis que c'est faussement simple. – Welbog

2

Utilisez break dans la boucle interne.

1

Vous voulez juste casser de l'intérieur qui continuerait l'extérieur.

while 
{ 
    // outer loop 

    while 
    { 
     // inner loop 
     try 
     { 
      throw; 
     } 
     catch 
     { 
      // how do I continue on the outer loop from here? 
      break; 
     } 
    } 
} 
0

Je pense que la meilleure façon d'y parvenir serait d'utiliser la déclaration break. Pause termine la boucle actuelle et continue l'exécution à partir de laquelle il se termine. Dans ce cas, il faut terminer la boucle interne et revenir dans la boucle extérieure. Voici à quoi ressemblerait votre code:

while 
{ 
    // outer loop 

    while 
    { 
     // inner loop 
     try 
     { 
      throw; 
     } 
     catch 
     { 
      // break jumps to outer loop, ends inner loop immediately. 
      break; //THIS IS THE BREAK 
     } 
    } 
} 

Je crois que c'est ce que vous cherchiez à accomplir, n'est-ce pas? Merci!

-2

Utilisez un propre type d'exception, par exemple MyException. Ensuite:

while 
{ 
    try { 
    // outer loop 
    while 
    { 
     // inner loop 
     try 
     { 
      throw; 
     } 
     catch 
     { 
      // how do I continue on the outer loop from here? 
      throw MyException; 
     } 
    } 
    } catch(MyException) 
    { ; } 
} 

Cela fonctionnera pour continuer et rompre plusieurs niveaux d'instructions while imbriquées. Désolé pour la mauvaise mise en forme;)

+4

Vous blessez mes sentiments, en utilisant des exceptions pour pas d'autre but que le contrôle du flux.Non downvote, juste blessé sentiments.:( –

+3

Cela me donne envie de vomir partout –

+2

C'est un peu plus emphatique que "blesser mes sentiments." –

22
while 
    { 
     // outer loop 

     while 
     { 
      // inner loop 
      try 
      { 
       throw; 
      } 
      catch 
      { 
       // how do I continue on the outer loop from here? 
       goto REPEAT; 
      } 
     } 
     // end of outer loop 
REPEAT: 
     // some statement or ; 
    } 

Problème résolu. (quoi? Pourquoi me donnez-vous ce regard sale?)

+1

Je vois ce que vous avez fait là – Mastenka

+2

Peut ne pas compiler, sauf si vous ajoutez explicitement un vide point-virgule de déclaration ('REPEAT:;') – matpop

0
using System; 

namespace Examples 
{ 

    public class Continue : Exception { } 
    public class Break : Exception { } 

    public class NestedLoop 
    { 
     static public void ContinueOnParentLoopLevel() 
     { 
      while(true) 
      try { 
       // outer loop 

       while(true) 
       { 
        // inner loop 

        try 
        { 
         throw new Exception("Bali mu mamata"); 
        } 
        catch (Exception) 
        { 
         // how do I continue on the outer loop from here? 

         throw new Continue(); 
        } 
       } 
      } catch (Continue) { 
        continue; 
      } 
     } 
    } 

} 

} 
Questions connexes