如何在 C# 中断开第一个 foreach 循环与第二个嵌套的 foreach 循环

本文关键字:foreach 循环 嵌套 第二个 第一个 中断 断开 | 更新日期: 2023-09-27 18:36:59

如何在C#中为每个循环从第二个嵌套的每个循环中首先中断,我想检查每个循环的第二个条件,然后尝试为每个循环中断父级

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                break;//but want to break first foreach loop
          }
     }
}

如何在 C# 中断开第一个 foreach 循环与第二个嵌套的 foreach 循环

快速回答:

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                goto end; // I'd probably add a comment here
          }
     }
     // *1
}
end:
{} // the rest of your code.
但是

,但是...

SESE 违规是违反单次进入单出口原则。通过使用额外的条件,它很容易修复:

bool found = false;
for (int i=0; i<foo.Count && !found; ++i)
{
    for (int j=0; j<bar.Count; ++j) 
    {
        if (...) { found = true; }
    }
    // *1 
    if (!found) { ... }
}

那么为什么在这里使用GOTO?

我相信创建适当的、可维护的代码意味着您使用最能描述您的意图的语言结构。这里的"代码"总是由两件事组成:

  • 控制流,通过forwhilebreakgoto等方式表示。
  • 数据流,通过表达式、变量和其他内存访问表示。

OP 的目的是打破嵌套循环,这相当于控制流操作。因此,我认为您应该使用最能代表意图的控制流操作 - 在这种情况下是goto

请注意,这根本不是你应该滥用到处引入goto语句的理由;如果你这样做,代码将变得非常难以阅读,这与可维护性和可读性无关。应将 goto 语句视为"最后手段的控制流"语句,在正确构建的代码中很少使用。

也就是说,在这种情况下,这意味着你不应该创建局部变量来处理控制流,除非这是绝对必要的(例如,如果没有可用的语言结构可以清楚地表达你的意图)。出于同样的原因,我不会在此特定场景中使用 Linq。

我想要性能。我该怎么办?

我相信大多数语言结构的滥用都是由于不理解编译器如何处理代码,这就是为什么我养成了解释它内部工作方式的习惯。请记住,我建议使用goto,因为它最清楚地描述了您的意图,而不是因为它可能更快一点。这里是:

想象一下成为编译器。您的代码中有 *1 点处有大量代码,无法使用 return .现在有两个选项:

  1. 您可以使用转到。
  2. 您可以使用额外的标志。

选项 1 将编译为具有内存的字段。内存是"稀缺"的,因为编译器将尽最大努力消耗尽可能少的内存,最好在寄存器中。这就是你的表现的来源。因此,编译器将尝试消除该标志。

为此,您的编译器将进行大量的流分析和其他内容,以尝试确定实际上存在两条代码路径:一条是在设置标志时,另一条是未设置标志时。

现在,如果你幸运的话,编译器会有它的"啊哈"时刻,并将你的代码从(2)更改为一个简单的GOTO,在这种情况下,天空仍然是蓝色的,每个人都很高兴。

但是,如果您不走运(并且发生这种情况有很多实际原因),它不会从流分析中检测到这一点,也不会创建 GOTO。由于您的标志在内部循环中使用,它甚至可能为此分配一个寄存器,这可能是最坏的情况。

如果您首先使用该goto,则无需所有这些。您只需为编译器提供正确的解决方案即可。简单。

Hrm 您有关于编译器如何做到这一点的更多详细信息吗?

是的,

看看钱德勒的这个2小时视频,它解释了很多关于编译器如何工作的信息: https://www.youtube.com/watch?v=FnGCDLhaxKU

-更新- 显然有些人误解了我的故事,正如@Groo所指出的那样。我做了一些调整,以澄清我想说的话。

你可以

通过使用"标志"来做到这一点

bool breakout = false
foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
             breakout = true;
             break;
          }
     }
     if(breakout)
      break;
}

如果你不能return,我建议使用 Linq,它让你的代码可读

Boolean found = false;
foreach(var item1 in source1.TakeWhile(_ => !found)) {
     foreach(var item2 in source2.TakeWhile(_ => !found)) {
          if (some condition)
          {
               found = true;
               //break; // Not necessary
          }
     }
}

您可以尝试使用这样的return

foreach(//do some stuff)
    foreach(//do some stuff)
       if(//check some condition)
          return;
您可以使用

WHILE。也许这段代码对你有帮助

foreach(// Some condition here)
{
    //solution
    bool breakme = false;
    while (// Some condition here)
    {
        foreach (// Some condition here)
        {
            if (// Condition again)
            {
                //Do some code
            }
            if (// Condition again)
            {
                //Stop the first foreach then go back to first foreach
                breakme = true;
                break;
            }
        }
    }
    if(breakme)
    {
        break;
    }
}
bool doBreak = false;
foreach(//do some stuff)
{
    foreach(//do some stuff)
    {
        doBreak = <check some condition>;
        if(doBreak) break;
    }
    if(doBreak) break;
}