如何在C#中退出while循环

74

我正在尝试跳出一个while循环。基本上,如果满足“if”条件,我希望能够退出这个循环:

我试图跳出while循环。如果满足"if"条件,我想要能够退出该循环:

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 >>
                }
            }
        }
    }
}

11
break;不起作用了吗? - Jon
@David - 是的,如果OP试图退出外部循环,这是使用goto的少数情况之一。 - Yakimych
@Yakimych 无稽之谈 :) 不幸的是,C#没有标记的break语句可以比goto更好地处理这个问题。 - user166390
1
@pst 什么是标记的break,它如何比goto更优? - David Heffernan
@David Heffeman 标记的break是一种在某些语言(如Java)中支持的goto子集 - 标签是控制结构的一部分,例如while。它与goto的不同之处在于它只能“跳出”该结构,因此在所有不需要完整的goto“功率”的情况下,更容易遵循。代码不能随意跳转,但是break 可以选择从哪个可能嵌套的循环中退出。请参见Java中的breakgoto的问题/优势在于它太不受限制了。 - user166390
显示剩余4条评论
7个回答

100

使用 break; 语句来跳出第一个循环:

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;
}

如果您想要同时避免第二个循环,您可能需要使用一个标记,并在外层循环的保护条件中进行检查:

        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;
                    }
                }
            }

或者,如果你想要在嵌套循环内完全退出函数,可以使用return;而不是break;

但这些实际上并不被认为是最佳实践。你应该找到一种方法将必要的布尔逻辑添加到你的while循环中。


11

breakgoto

while ( true ) {
  if ( conditional ) {
    break;
  }
  if ( other conditional ) {
    goto EndWhile;
  }
}
EndWhile:

19
"Goto"是一件令人敬畏的事情。 - Rafael Herscovici
9
并非在所有情况下都是如此。如果使用得当,它可以增加可读性,帮助退出深度嵌套的循环,转移到特定的switch case标签等。就像zellio上面的示例所示,它可以帮助不使用任何其他变量等退出。常见的goto用法是将控制传输到switch-case标签或switch语句中的默认标签。goto语句还有助于退出深度嵌套的循环。来源:https://msdn.microsoft.com/en-us/library/13940fs2(v=vs.71).aspx - sandiejat
2
当我们在while循环中使用'switch'关键字时,它不起作用,因此只需向while添加另一个测试条件,例如bool bTurnOff = false; while(true && bTurnOff == false) {...}。 - TomeeNS

5

但是你也可以考虑另一种非常不同的方法,即监听文件系统事件。

点击此处了解更多信息。

@Bobby 有趣的方法 - Nic
文档已过时,此答案不再相关。 - Roe

4
如果您需要继续使用其他逻辑,使用以下代码:...
break;

如果您有需要返回的值...
return my_value_to_be_returned;

然而,通过查看您的代码,我相信您可以使用下面修订后的示例来控制循环,而无需使用break或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;
                        }
                    }
                }
            }
        }

2

你想要退出哪个循环?简单的break;语句可以退出内部循环。对于外部循环,你可以使用一个外部循环范围的变量(例如布尔型变量exit = false;),在你中断内部循环之前将其设置为true。在内部循环块后检查exit的值,如果为true,则再次使用break;


+1 是因为考虑了两个循环(而没有提到四字关键词)。 - Joel Rondeau

1
"

"break"是一个命令,可以中断“最近”的循环。

虽然使用"break"有很多好处,但如果没有必要,就不应该使用它——因为它可能被视为使用goto的另一种方式,而goto被认为是不好的。

例如,为什么不这样做:

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

如果你使用 "break" 的原因是因为你不想继续执行该循环的这一次迭代,那么你可能想要使用 "continue" 关键字,它会立即跳到下一个迭代,无论是 while 还是 for 循环。

while (!condition) {
   //Some code
   if (condition) continue;
   //More code that will be skipped over if the condition was true
}

7
"只有教条主义者认为break是坏事。所有关键词都可以被滥用,但也都可以被正当使用。" - David Heffernan

0

抱歉打扰,但是有一些我真的很想插入的东西,在现有答案中缺失(对于像我这样通过谷歌偶然发现这个问题的人):重构你的代码。不仅它会让代码更易读/易维护,而且通常还会完全消除这些控制流程问题。

如果我需要编写上述函数,这是我倾向的方式:

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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接