Kontynuuj w zagnieżdżonych pętlach while

W tej próbce kodu, czy jest jakiś sposób, aby kontynuować na zewnętrznej pętli z bloku catch?

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           continue;
       }
   }
}
Author: SkunkSpinner, 2009-07-15

10 answers

Aktualizacja: to pytanie było inspiracją dla mojego artykułu na ten temat. dzięki za świetne pytanie!


"continue " i" break "to nic innego jak przyjemna składnia dla "goto". Najwyraźniej nadając im słodkie nazwy i ograniczając ich użycie do konkretnych struktur kontrolnych, nie przyciągają już ire tłumu "wszyscy Goto są źli cały czas".

Jeśli to, co chcesz zrobić, jest kontynuacją do zewnątrz, Może po prostu zdefiniować etykietę w górna część zewnętrznej pętli, a następnie "goto" ta etykieta. Jeśli uważasz, że nie utrudniło to zrozumiałości kodu, to może to być najbardziej wskazane rozwiązanie.

Jednak potraktowałbym to jako okazję do rozważenia, czy twój przepływ sterowania skorzystałby na jakiejś refaktoryzacji. Ilekroć mam warunkowe "break" I "continue" w zagnieżdżonych pętlach, rozważam refaktoryzację.

Rozważmy:

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

Dwie techniki refaktoryzacji:

Po pierwsze, Wyciąg pętla wewnętrzna do metody:

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

Po drugie, czy wszystkie pętle można wyeliminować? Jeśli zapętlasz się, ponieważ próbujesz czegoś wyszukać, przefaktoruj to do zapytania.

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
}

Jeśli nie ma pętli, nie ma potrzeby przerywania lub kontynuowania!

 111
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-15 19:54:36
    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 ; 
    }
Problem rozwiązany. (co?? Dlaczego tak na mnie patrzycie?)
 37
Author: ryansstack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-18 21:03:08

Możesz użyć wyrażenia break;.

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

Continue służy do powrotu do górnej części pętli prądowej.

Jeśli chcesz przełamać więcej poziomów, musisz albo dodać jakieś "jeśli", albo użyć przerażającego / nie zalecanego "goto".

 20
Author: Jake Pearson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:23:26

Zamień strukturę try/catch na wewnętrzną pętlę while:

while {
  try {
    while {
      throw;
    }
  }
  catch {
    continue;
  }
}
 10
Author: Welbog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:22:00

Nie.
Proponuję wyodrębnić wewnętrzną pętlę w osobną metodę.

while
{
   // outer loop
       try
       {
           myMethodWithWhileLoopThatThrowsException()
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           continue;
       }
   }
}
 4
Author: shahkalpesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:23:13

Użyj break w wewnętrznej pętli.

 4
Author: Marco Mustapic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:23:37

Chcesz po prostu oderwać się od tego, co wewnętrzne, co kontynuuje to, co zewnętrzne.

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           break;
       }
   }
}
 1
Author: David Basarab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:24:17
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;
            }
        } 
    }

}

}
 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-23 15:37:08

Myślę, że najlepszym sposobem, aby to osiągnąć, byłoby użycie break . Break kończy pętlę bieżącą i kontynuuje wykonywanie z miejsca, w którym się kończy. W tym przypadku, to zakończy wewnętrzną pętlę i wskoczy z powrotem do zewnętrznej pętli while. Tak wyglądałby Twój kod:

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // break jumps to outer loop, ends inner loop immediately.
           break; //THIS IS THE BREAK
       }
   }
}
Wierzę, że to właśnie chciałeś osiągnąć, prawda? Dzięki!
 0
Author: Maxim Zaslavsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:35:32

Użyj własnego typu wyjątku, np. MyException. Wtedy:

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

Będzie to działać do kontynuowania i wyłamywania się z kilku poziomów poleceń zagnieżdżonych while. Sorry za złe formatowanie;)

 -2
Author: zvrba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-15 19:41:41