如何在 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
}
}
}
快速回答:
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?
我相信创建适当的、可维护的代码意味着您使用最能描述您的意图的语言结构。这里的"代码"总是由两件事组成:
- 控制流,通过
for
、while
、break
和goto
等方式表示。 - 数据流,通过表达式、变量和其他内存访问表示。
OP 的目的是打破嵌套循环,这相当于控制流操作。因此,我认为您应该使用最能代表意图的控制流操作 - 在这种情况下是goto
。
请注意,这根本不是你应该滥用到处引入goto
语句的理由;如果你这样做,代码将变得非常难以阅读,这与可维护性和可读性无关。应将 goto
语句视为"最后手段的控制流"语句,在正确构建的代码中很少使用。
也就是说,在这种情况下,这意味着你不应该创建局部变量来处理控制流,除非这是绝对必要的(例如,如果没有可用的语言结构可以清楚地表达你的意图)。出于同样的原因,我不会在此特定场景中使用 Linq。
我想要性能。我该怎么办?
我相信大多数语言结构的滥用都是由于不理解编译器如何处理代码,这就是为什么我养成了解释它内部工作方式的习惯。请记住,我建议使用goto
,因为它最清楚地描述了您的意图,而不是因为它可能更快一点。这里是:
想象一下成为编译器。您的代码中有 *1 点处有大量代码,无法使用 return
.现在有两个选项:
- 您可以使用转到。
- 您可以使用额外的标志。
选项 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;
}