C# 摆脱多重循环?
可能重复:C# 摆脱多重循环?,c#,loops,foreach,break,goto,C#,Loops,Foreach,Break,Goto,可能重复: 我有这个密码 foreach (___) { foreach (___) { foreach (___) { if (condition) { //break out of all loops } } } } 但是break只“打断”了最内部的循环(对不起,我的英语),我想把它们都留下 我在想: 后藤,但我
我有这个密码
foreach (___)
{
foreach (___)
{
foreach (___)
{
if (condition)
{
//break out of all loops
}
}
}
}
但是break
只“打断”了最内部的循环(对不起,我的英语),我想把它们都留下
我在想:
提前感谢您的帮助 A
goto
在这里非常好:
foreach (___)
{
foreach (___)
{
if (condition)
{
goto done;
}
}
}
done: ;
也许这是使用
goto
的唯一有效原因。一个非常优雅的解决方案是将整个循环嵌套移动到一个单独的方法中,然后返回当你想打破所有的循环时。几年前,当我还在学校的时候,我们有一个很笨的老师教信息学。其中一条规则是“不去”。我有一个包含多个循环的算法,在没有goto的情况下,循环的大小增加了很多倍
有很好的理由,打破多个循环就是其中之一。最好的方法可能是用返回语句重构成更小的方法。但是,如果您需要范围中的许多变量,您可以始终使用委托
bool bLoopBreak = false;
foreach (___)
{
foreach (___)
{
foreach (___)
{
if (condition)
{
bLoopBreak = true;
break;
//break out of all loops
}
}
if (bLoopBreak) break;
}
if (bLoopBreak) break;
}
Action work = delegate
{
foreach (___)
{
foreach (___)
{
foreach (___)
{
if (condition)
{
return;
}
}
}
}
};
work();
在这种情况下,不要害怕使用goto
break
和continue
只是goto
的语法糖分,并且是有节制和正确注释的。它可以使代码比许多嵌套检查更清晰,以查看是否应该停止循环。PHP允许您这样做:
foreach (___)
{
foreach (___)
{
foreach (___)
{
break 3; // get out of all 3 loops
}
}
}
我对C不太了解,但它可能有一个类似的特性。只是在其中抛出一个替代方案:您也可以在循环中抛出一个异常。在C#/Java/Python中,这样做相当便宜。(C++中,不是那么多)
请注意,对于类似的情况,Python有一个StopIteration
异常,因此这并非闻所未闻,尽管在C#land中可能有点不正常
有时,您可以免费获得异常,因此可以使用它,但如果您采用这种方法,则最好将其记录下来
try {
foreach (___) {
foreach (___) {
if(your condition true) {
throw new IterationDone(); // or use a singleton to avoid allocating
}
}
}
// not found
catch (IterationDone e) {
// yay
}
我把答案做成了一个社区维基,这样就可以看到和讨论它了。(我不主张它是第一个也是最好的解决方案,它只是一个解决方案,因此应该在这里……+1因为我不害怕!)看见我声称,人们对此持否定态度,并不真正理解为什么goto
被认为是有害的,只是回避它,因为他们经常听到goto是邪恶的
咒语(这在原则上是正确的,但仅在原则上)。除了使用方法进行重构,我没有见过比goto
更干净、可读性更强的解决方案来解决这个问题。@Heinzi,在这里使用goto
可能没问题,但你最终会浪费很多时间与同事争论这个问题。最好把它重构成一个单独的函数。@avakar:如果你的同事很愚蠢,教育他们,或者忽略他们。使用错误的解决方案来取悦他们的无知绝对不是正确的做法。如果从循环中访问一组局部变量,这可能不起作用,尽管如此。想更详细地解释下一票的原因吗?@TomTom:这是什么原因?@RobertRouhani+1抵消了一个似是而非且无法解释的下一票+1,用于重构以避免高嵌套。这很聪明,但它只会在第一次迭代后打破自己的for循环。@RobertRouhani开玩笑。显然一点也不好笑。我认为相同的问题在link@JérémyTalio中得到了回答:与您的问题无关,也有可能通过某种方式对代码进行重构以避免嵌套循环,但如果没有这些循环中的实际代码,这是不可能的。我从来没有在一个函数中有过那么多嵌套循环,也不需要突破那么多。也许重写代码就是解决方案。还要学习使用Contains函数(来自linq)。+1,因为这是本线程中布尔标志解决方案的最佳示例,但请注意,问题要求“使用比布尔标志更优雅的方式”,因此从技术上讲,这不是答案。不是真正可维护的代码。。改为使用函数+返回解决方案。如果我遇到像这样的问题,我会将文件废弃,然后再重新处理。@Lohoris你可以随意废弃,我在这里发布并不是因为我得到报酬,我在这里发布是因为人们可能会发现我的答案很有用。如果它不适合你,欢迎你忽略它。我不想在这里投反对票,但我讨厌看到代码更复杂、更容易出错、更慢,只是因为它的坏名声而避免完美的语言结构。这是一种非常讨厌的绕过转到
的方法:-D意识到返回值
只会退出匿名方法需要更多的时间。@Groo可以肯定,这只是Robert Rouhani自己对其接受答案的评论的一个边缘案例解决方案。为了更加隐蔽,我会省略变量,并在声明后简单地调用委托:委托{…}()代码>:-D只是开玩笑,它和这里的任何其他示例一样完全有效。我仍然可能会将其提取到一个方法中,尽管三个嵌套的foreach
循环很可能可以使用LINQ或其他东西进行重构。@Groo为什么?有了一个明确的标签,就有可能从其他地方跳转到它(有人告诉我);这里的显式标签被删除了,所以,很好,不是吗?我也有点喜欢你的第二个建议,取消另一个明确的使用名称。顺便说一句,Common Lisp有命名作用域,从中返回可以从任何命名作用域转义,而不仅仅是方法(函数)的命名作用域。不,它没有这样的特性。这是一个伪装成中断的goto,是伪装成中断的goto;这样的代码容易出现可怕的错误:如果在所有中断之间添加一个循环,那么祝您好运找到发生的事情!关于“语法糖”你完全错了。它们经过语义检查、范围限定和编译器确认为“sugar”。就像任何if
和for
一样