web-dev-qa-db-fra.com

Continuer dans les boucles imbriquées

Dans cet exemple de code, existe-t-il un moyen de continuer sur la boucle externe à partir du bloc catch?

while
{
   // outer loop

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

MISE À JOUR: Cette question a été une source d'inspiration pour mon article sur ce sujet. Merci pour la grande question!


"continue" et "break" ne sont rien d'autre qu'une syntaxe agréable pour un "goto". Apparemment, en leur donnant des noms mignons et en restreignant leurs usages à des structures de contrôle particulières, ils n'attirent plus la colère de la foule "tous les gotos sont tous mauvais tout le temps".

Si ce que vous voulez faire est une continuation vers l'extérieur, vous pourriez simplement définir une étiquette en haut de la boucle externe puis "goto" cette étiquette. Si vous estimiez que cela ne gênait pas la compréhensibilité du code, alors cela pourrait être la solution la plus opportune.

Cependant, je saisirais cela comme une opportunité pour examiner si votre flux de contrôle bénéficierait d'une refactorisation. Chaque fois que j'ai une "pause" conditionnelle et une "poursuite" dans les boucles imbriquées, je pense à une refactorisation.

Considérer:

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 refactoring:

Tout d'abord, extrayez la boucle interne d'une méthode:

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

Deuxièmement, toutes les boucles peuvent-elles être éliminées? Si vous effectuez une boucle parce que vous essayez de rechercher quelque chose, refactorisez-le dans 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 boucles, il n'est pas nécessaire de rompre ou de continuer!

97
Eric Lippert
    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 tous ce regard sale?)

30
ryansstack

Vous pouvez utiliser une pause; déclaration.

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

Continuer est utilisé pour revenir en haut de la boucle actuelle.

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

18
Jake Pearson

Échangez la structure try/catch avec la boucle while intérieure:

while {
  try {
    while {
      throw;
    }
  }
  catch {
    continue;
  }
}
10
Welbog

Non.
Je suggère, en extrayant la boucle intérieure dans une méthode distincte.

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

Utilisez break dans la boucle interne.

3
Marco Mustapic

Vous voulez juste rompre avec l'intérieur qui continuerait avec l'extérieur.

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           break;
       }
   }
}
1
David Basarab
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;
            }
        } 
    }

}

}
0
elitsa

Je pense que la meilleure façon d'y parvenir serait d'utiliser l'instruction break. Break termine la boucle en cours et continue l'exécution de l'endroit où elle se termine. Dans ce cas, il faudrait terminer la boucle interne et revenir dans la boucle while externe. 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!

0
Maxim Zaslavsky