77

In this code sample, is there any way to continue on the outer loop from the catch block?

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           continue;
       }
   }
}
SkunkSpinner
  • 11,429
  • 7
  • 40
  • 53
  • 21
    Nested loops only lead to despair. – Michael Meadows Jul 15 '09 at 19:51
  • 4
    I find it ironic that SO will close a question if you ask for an opinion from the group of experts, but the 'experts' have absolutely no qualms about sharing unsolicited and often ignorant opinions as opposed to simply answering the 'fact seeking' question we are told we have to ask. – greg May 10 '22 at 16:27
  • I agree Greg. Michael in future if you are going to comment like this please actually answer the question or provide some links as well. – Slipoch Jul 03 '23 at 01:58

11 Answers11

124

UPDATE: This question was inspiration for my article on this subject. Thanks for the great question!


"continue" and "break" are nothing more than a pleasant syntax for a "goto". Apparently by giving them cute names and restricting their usages to particular control structures, they no longer draw the ire of the "all gotos are all bad all the time" crowd.

If what you want to do is a continue-to-outer, you could simply define a label at the top of the outer loop and then "goto" that label. If you felt that doing so did not impede the comprehensibility of the code, then that might be the most expedient solution.

However, I would take this as an opportunity to consider whether your control flow would benefit from some refactoring. Whenever I have conditional "break" and "continue" in nested loops, I consider refactoring.

Consider:

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

Two refactoring techniques:

First, extract the inner loop to a method:

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

Second, can all the loops be eliminated? If you are looping because you are trying to search for something, then refactor it into a query.

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
}

If there are no loops then there is no need to break or continue!

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 11
    +1 for "...extract the inner loop to a method." I require lot of justification in code reviews when I see nested loops. They usually hurt readability, maintainability, and stability. OP's question can be solved with a simple "return" or "throw" (thereby not relying on gotos in any way). – Michael Meadows Jul 15 '09 at 19:50
  • 9
    Absolutely. When you think you need a `goto`, first stop for a moment and ponder if you really do. If you still need a `goto`, then just use it - it's in the language for a reason. It's not inherently evil either - it just commonly appears in evil patterns, and therefore should serve as a signal to stop and try to spot such patterns (and not to plunge into "OMG `goto` this is all wrong" panic). – Pavel Minaev Jul 16 '09 at 00:35
  • 2
    Goto is not inherently evil, but it is a gateway drug to bad, lazy code. Of all of the ways to control flow, it's *usually* the worst. – Michael Meadows Jul 16 '09 at 14:44
  • 2
    Don't forget to add `using System.Linq` for the second refactoring technique. – Matthew Steven Monkan Jun 30 '11 at 18:27
  • 1
    gotos are bad all the time, unless you are a compilert or eric lipper – jeremy-george Apr 15 '13 at 21:49
  • 2
    So verbose, where is continue {nameOfLoop} like Java.. :-( – Oliver Dixon Aug 06 '16 at 19:11
  • 1
    The second refactoring introduces the need for allocation (enumerables and enumerators implementing the query and its evaluation) and is generally slower than the loop as it does strictly more work. It may be negligible and outweighed by the gains in readability, but it may not. Good to keep that in mind. – Palec Aug 26 '17 at 10:30
  • Something to bear in mind - System.Linq is using SQL statements (linq queries) are VERY expensive (by like a factor of 10-20x usually) over loops. – Slipoch Jul 03 '23 at 02:00
46
    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 solved. (what?? Why are you all giving me that dirty look?)

ryansstack
  • 1,396
  • 1
  • 15
  • 33
22

You can use a break; statement.

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

Continue is used to jump back to the top of the current loop.

If you need to break out more levels than that you will either have to add some kind of 'if' or use the dreaded/not recommended 'goto'.

Jake Pearson
  • 27,069
  • 12
  • 75
  • 95
  • 4
    The problem with this method is if there is extra work that needs to be done between the end of the inner loop and the end of the outer loop, it will be done when calling `break`, but wouldn't be done when calling `continue`. You'd need a flag if you need that code to not be executed. I'm not saying that this answer is wrong (heck, I upvoted it), I'm saying that it's deceptively simple. – Welbog Jul 15 '09 at 19:31
10

Swap the try/catch structure with the inner while loop:

while {
  try {
    while {
      throw;
    }
  }
  catch {
    continue;
  }
}
Welbog
  • 59,154
  • 9
  • 110
  • 123
5

No.
I suggest, extracting the inner loop into a separate method.

while
{
   // outer loop
       try
       {
           myMethodWithWhileLoopThatThrowsException()
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           continue;
       }
   }
}
shahkalpesh
  • 33,172
  • 3
  • 63
  • 88
  • This is problematic because the separate metod will not have access to existing local variables. – zvrba Jul 15 '09 at 19:34
  • 7
    That's why Microsoft gave us function parameters. – Welbog Jul 15 '09 at 19:36
  • pass the variables as parameters, or if side-effects are necessary, send it through as an anonymous delegate to be executed in the method. Then the compiler will create a closure, preserving your local scope. – Michael Meadows Jul 15 '09 at 19:54
  • 5
    You also should not be using the exception handling process for normal code control flow – Brian Leeming Oct 14 '11 at 18:18
  • That's why Microsoft gave us "local functions" (since C# 7 and Visual Studio 2017) which do not need any parameters because they have access to all local variables of outer functions. – palota Feb 03 '21 at 21:58
  • @palota You cant really fault a guy for not knowing a feature that comes out 8 years after he posted that comment.. – AustinWBryan Apr 04 '22 at 21:59
3

Use break in the inner loop.

Marco Mustapic
  • 3,879
  • 1
  • 21
  • 20
0

You just want to break from the inner which would continue the outer.

while
{
   // outer loop

   while
   {
       // inner loop
       try
       {
           throw;
       }
       catch 
       {
           // how do I continue on the outer loop from here?
           break;
       }
   }
}
David Basarab
  • 72,212
  • 42
  • 129
  • 156
0

If you wish to use try catch, simply move them outwards (although I would recommend refactoring).

I would only do this if it IS an error and needs logging, I would also push

while
{
    try 
    {
        DoStuffToThisElement(item);
    }
    catch(Exception ex)
    {
        logError(ex);
    }
}

private void  DoStuffToThisElement(Item item)
{
    while
    {
        if(condition)
        {
            throw;
        }
    }
}
Slipoch
  • 750
  • 10
  • 23
-1

I think the best way to accomplish this would be to use the break statement. Break ends the current loop and continues execution from where it ends. In this case, it would end the inner loop and jump back into the outer while loop. This is what your code would look like:

while
{
   // outer loop

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

I believe that is what you were looking to be accomplished, correct? Thanks!

Maxim Zaslavsky
  • 17,787
  • 30
  • 107
  • 173
-2
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;
            }
        } 
    }

}

}
-4

Use an own exception type, e.g., MyException. Then:

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

This will work for continuing and breaking out of several levels of nested while statements. Sorry for bad formatting ;)

zvrba
  • 24,186
  • 3
  • 55
  • 65