Continue in nested while loops
Solution 1
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!
Solution 2
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?)
Solution 3
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'.
Solution 4
Swap the try/catch structure with the inner while loop:
while {
try {
while {
throw;
}
}
catch {
continue;
}
}
Solution 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;
}
}
}
Comments
-
SkunkSpinner over 3 years
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; } } }
-
Welbog almost 15 yearsThe 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 callingcontinue
. 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. -
zvrba almost 15 yearsThis is problematic because the separate metod will not have access to existing local variables.
-
Welbog almost 15 yearsThat's why Microsoft gave us function parameters.
-
Michael Meadows almost 15 years+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 almost 15 yearspass 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 almost 15 yearsYou hurt my feelings, using exceptions for no other purpose than flow control. No downvote, just hurt feelings. :(
-
Summer Sun almost 15 yearsThis makes me want to vomit everywhere
-
Michael Meadows almost 15 yearsThat's a little more emphatic than "hurt my feelings."
-
Pavel Minaev almost 15 yearsAbsolutely. When you think you need a
goto
, first stop for a moment and ponder if you really do. If you still need agoto
, 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 "OMGgoto
this is all wrong" panic). -
Michael Meadows almost 15 yearsGoto 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.
-
Matthew Steven Monkan almost 13 yearsDon't forget to add
using System.Linq
for the second refactoring technique. -
Brian Leeming over 12 yearsYou also should not be using the exception handling process for normal code control flow
-
jeremy-george about 11 yearsgotos are bad all the time, unless you are a compilert or eric lipper
-
Mastenka over 8 yearsI see what you did there
-
matpop about 8 yearsMay not compile unless you explicitly add an empty statement semicolon (
REPEAT: ;
) -
Oliver Dixon over 7 yearsSo verbose, where is continue {nameOfLoop} like Java.. :-(
-
Palec over 6 yearsThe 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.
-
sinedsem almost 4 yearsDoesn't work if you have some code in outer loop after inner loop.
-
palota about 3 yearsThat'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.
-
Jim G. about 3 yearsDuplicate: stackoverflow.com/a/1133427/109941
-
Jim G. about 3 yearsDuplicate: stackoverflow.com/a/1133427/109941
-
AustinWBryan about 2 years@palota You cant really fault a guy for not knowing a feature that comes out 8 years after he posted that comment..