74

I am trying to escape a while loop. Basically, if the "if" condition is met, I would like to be able to exit this loop:

private void CheckLog()
{
    while (true)
    {
        Thread.Sleep(5000);
        if (!System.IO.File.Exists("Command.bat"))
            continue;

        using (System.IO.StreamReader sr = System.IO.File.OpenText("Command.bat"))
        {
            string s = "";
            while ((s = sr.ReadLine()) != null)
            {
                if (s.Contains("mp4:production/CATCHUP/"))
                {
                    RemoveEXELog();

                    Process p = new Process();
                    p.StartInfo.WorkingDirectory = "dump";
                    p.StartInfo.FileName = "test.exe";
                    p.StartInfo.Arguments = s;
                    p.Start();

                    << Escape here - if the "if" condition is met, escape the loop here >>
                }
            }
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James
  • 1,459
  • 3
  • 16
  • 15
  • 11
    `break;` does not work? – Jon Jul 16 '11 at 19:17
  • @David - Yes, and if the OP is trying to exit the outer loop, this is one of the rare cases where using `goto` is a good idea. – Yakimych Jul 16 '11 at 19:22
  • @Yakimych Nonsense :) Unfortunately C# does not have a labeled break which cleanly handles this *better* than a `goto`. –  Jul 16 '11 at 19:23
  • 1
    @pst what is labelled break and how is it superior to goto? – David Heffernan Jul 16 '11 at 19:28
  • @David Heffeman A labeled break is a subset of a `goto` supported in some languages like Java -- the label is part of the control structure such as `while`. It differs from `goto` in that it can only "break out" of that structure and thus -- in all the cases where the full "power" of a `goto` is not needed -- is easier to follow. The code *can't jump willy-nilly* but a break *can* choose from which, possibly nested, loop to break from. [See `break` in Java](http://download.oracle.com/javase/tutorial/java/nutsandbolts/branch.html). The problem/power with `goto` is that it is *too unrestricted*. –  Jul 16 '11 at 21:23
  • @David Heffeman Of course a labeled break is less general than a [`throw/catch` as in Common Lisp](http://abhishek.geek.nz/docs/features-of-common-lisp/) or [in Ruby](http://ruby.activeventure.com/programmingruby/book/tut_exceptions.html) -- however, unlike a `goto`, said "throw/catch" is similar to an Exception (without the implied "Exception" bit) in that it can only *unwind through scopes/blocks*. Once again, it *can't jump willy-nilly*. I honestly can't justify `goto` *in a high-level language* (I don't consider C high-level ;-) vs. other constructs that exist. –  Jul 16 '11 at 21:26
  • @pst Thanks for that. Labelled break does indeed sound good. I agree regarding the utility of goto in languages that support exceptions - it is not needed. When you don't have exceptions, i.e. C, then goto can be helpful. – David Heffernan Jul 16 '11 at 21:33
  • How was such a basic question not a duplicate at the time (nearly 3 years after Stack Overflow was launched)? – Peter Mortensen Aug 07 '14 at 16:03
  • @Yakimych A bit late on the reply - but there is never a good case to use GOTO (in OOP languages). As others have suggested, `break` is sufficient in this case. – waqasahmed Jul 22 '18 at 13:46

7 Answers7

98

Use break; to escape the first loop:

if (s.Contains("mp4:production/CATCHUP/"))
{
   RemoveEXELog();
   Process p = new Process();
   p.StartInfo.WorkingDirectory = "dump";
   p.StartInfo.FileName = "test.exe"; 
   p.StartInfo.Arguments = s; 
   p.Start();
   break;
}

If you want to also escape the second loop, you might need to use a flag and check in the out loop's guard:

        boolean breakFlag = false;
        while (!breakFlag)
        {
            Thread.Sleep(5000);
            if (!System.IO.File.Exists("Command.bat")) continue;
            using (System.IO.StreamReader sr = System.IO.File.OpenText("Command.bat"))
            {
                string s = "";
                while ((s = sr.ReadLine()) != null)
                {
                    if (s.Contains("mp4:production/CATCHUP/"))
                    {

                        RemoveEXELog();

                        Process p = new Process();
                        p.StartInfo.WorkingDirectory = "dump";
                        p.StartInfo.FileName = "test.exe"; 
                        p.StartInfo.Arguments = s; 
                        p.Start();

                        breakFlag = true;
                        break;
                    }
                }
            }

Or, if you want to just exit the function completely from within the nested loop, put in a return; instead of a break;.

But these aren't really considered best practices. You should find some way to add the necessary Boolean logic into your while guards.

Dirk
  • 3,030
  • 1
  • 34
  • 40
11

break or goto

while ( true ) {
  if ( conditional ) {
    break;
  }
  if ( other conditional ) {
    goto EndWhile;
  }
}
EndWhile:
zellio
  • 31,308
  • 1
  • 42
  • 61
  • 19
    `Goto` is an awe-full thing. – Rafael Herscovici Jun 22 '14 at 15:25
  • 9
    @Dementic - Not in every case. If used smartly, it can increase readability, can help exit out a deeply nested loop, transfer control to a specific switch case label etc. Like shown in above example by zellio, it helps exiting out without using any other variable etc. From https://msdn.microsoft.com/en-us/library/13940fs2(v=vs.71).aspx "A common use of goto is to transfer control to a specific switch-case label or the default label in a switch statement. The goto statement is also useful to get out of deeply nested loops." – sandiejat Mar 10 '17 at 01:12
  • 2
    It doesnt not work when we use 'switch' keyword in a 'while' loop, so just add another test conditon to the while e.g. bool bTurnOff = false; while (true && bTurnOff == false) {...} – TomeeNS Jul 12 '17 at 22:12
5

But you might also want to look into a very different approach, listening for file-system events.

Bobby
  • 11,419
  • 5
  • 44
  • 69
Tim
  • 5,371
  • 3
  • 32
  • 41
4

If you need to continue with additional logic use...

break;

or if you have a value to return...

return my_value_to_be_returned;

However, looking at your code, I believe you will control the loop with the revised example below without using a break or return...

private void CheckLog()
        {
            bool continueLoop = true;
            while (continueLoop)
            {
                Thread.Sleep(5000);
                if (!System.IO.File.Exists("Command.bat")) continue;
                using (System.IO.StreamReader sr = System.IO.File.OpenText("Command.bat"))
                {
                    string s = "";
                    while (continueLoop && (s = sr.ReadLine()) != null)
                    {
                        if (s.Contains("mp4:production/CATCHUP/"))
                        {
                            RemoveEXELog();

                            Process p = new Process();
                            p.StartInfo.WorkingDirectory = "dump";
                            p.StartInfo.FileName = "test.exe"; 
                            p.StartInfo.Arguments = s; 
                            p.Start();
                            continueLoop = false;
                        }
                    }
                }
            }
        }
Alban
  • 704
  • 1
  • 6
  • 11
2

Which loop are you trying to exit? A simple break; will exit the inner loop. For the outer loop, you could use an outer loop-scoped variable (e.g. boolean exit = false;) which is set to true just before you break your inner loop. After the inner loop block check the value of exit and if true use break; again.

tomfumb
  • 3,669
  • 3
  • 34
  • 50
1

"break" is a command that breaks out of the "closest" loop.

While there are many good uses for break, you shouldn't use it if you don't have to -- it can be seen as just another way to use goto, which is considered bad.

For example, why not:

while (!(the condition you're using to break))
        {
         //Your code here.
        }

If the reason you're using "break" is because you don't want to continue execution of that iteration of the loop, you may want to use the "continue" keyword, which immediately jumps to the next iteration of the loop, whether it be while or for.

while (!condition) {
   //Some code
   if (condition) continue;
   //More code that will be skipped over if the condition was true
}
Jeremy
  • 5,365
  • 14
  • 51
  • 80
0

Sorry for the necro-add, but there's something I really wanted to insert that's missing in the existing answers (for anyone like me stumbling onto this question via google): refactor your code. Not only will it make it easier to read/maintain, but it'll often remove these types of control-routing issues entirely.

Here's what I'd lean towards if I had to program the function above:

private const string CatchupLineToIndicateLogDump = "mp4:production/CATCHUP/";
private const string BatchFileLocation = "Command.bat";

private void CheckLog()
{
    while (true)
    {
        Thread.Sleep(5000);
        if (System.IO.File.Exists(BatchFileLocation))
        {
            if (doesFileContainStr(BatchFileLocation, CatchupLineToIndicateLogDump))
            {
                RemoveLogAndDump();
                return;
            }
        }
    }
}

private bool doesFileContainStr(string FileLoc, string StrToCheckFor)
{
  // ... code for checking the existing of a string within a file
  // (and returning back whether the string was found.)
}

private void RemoveLogAndDump()
{
  // ... your code to call RemoveEXELog and kick off test.exe
}
Kevin
  • 2,133
  • 1
  • 9
  • 21