C# 跳出嵌套循环可以吗?
JavaScript支持类似goto的语法来打破嵌套循环。一般来说,这不是一个好主意,但被认为是可以接受的做法。C#不直接支持C# 跳出嵌套循环可以吗?,c#,javascript,C#,Javascript,JavaScript支持类似goto的语法来打破嵌套循环。一般来说,这不是一个好主意,但被认为是可以接受的做法。C#不直接支持break labelName语法……但它支持臭名昭著的goto 我相信C#也可以达到同样的效果: inti=0; 而(i)(5) { 转到断开;//断开所有循环 } } 中断: 按照JavaScript的相同逻辑,嵌套循环场景是否可以接受使用goto?否则,我知道实现此功能的唯一方法是通过设置具有适当范围的bool。IMO在不支持break n的语言中,这是可以接受的
break labelName
语法……但它支持臭名昭著的goto
我相信C#也可以达到同样的效果:
inti=0;
而(i)(5)
{
转到断开;//断开所有循环
}
}
中断:
按照JavaScript的相同逻辑,嵌套循环场景是否可以接受使用
goto
?否则,我知道实现此功能的唯一方法是通过设置具有适当范围的bool
。IMO在不支持break n的语言中,这是可以接受的代码>其中n
指定它应该中断的循环数。
至少它比设置一个在外部循环中检查的变量可读性好得多。我相信在这种情况下“goto”是可以接受的。不幸的是,C#不支持任何巧妙的方法来打破嵌套循环。在C#中是不可接受的
只需将循环包装在函数中并使用return
编辑:因此,向下投票习惯于对错误答案进行投票,而不是对您不同意的答案进行投票。正如OP明确地问到的“它可以接受吗?”,回答“不可接受”并不是不正确的(尽管您可能不同意)。我个人会尝试通过简单地将循环放入不同的方法来避免在这里使用goto-虽然您不能轻易地打破特定级别的循环,但您可以在任何时候轻松地从方法返回
根据我的经验,这种方法通常会导致更简单、更可读的代码,方法通常更短(做一项特定的工作)。让我们澄清一件事:使用goto
语句从根本上说没有什么错,它不是坏事——它只是工具箱中的又一个工具。真正重要的是你如何使用它,它很容易被误用
打破某种描述的嵌套循环可能是对该语句的有效使用,尽管您应该首先查看它是否可以重新设计。可以重写循环出口表达式吗?您是否使用了适当的循环类型你能过滤你可能要迭代的数据列表,这样你就不需要提前退出吗?你应该把一些循环代码重构成一个单独的函数吗?这在C#中有点不可接受。如果你的设计无法避免的话,那就得使用它。但首先要用尽所有其他选择。它将提高可读性和可维护性。在您的示例中,我精心设计了一个这样的潜在重构:
void Original()
{
int i = 0;
while(i <= 10)
{
Debug.WriteLine(i);
i++;
if (Process(i))
{
break;
}
}
}
bool Process(int i)
{
for(int j = 0; j < 3; j++)
if (i > 5)
{
return true;
}
return false;
}
void Original()
{
int i=0;
而(i)(5)
{
返回true;
}
返回false;
}
我的观点:带有嵌套循环的复杂代码流很难推理;分支,无论是goto还是break,只会让事情变得更难。与其编写goto,我首先要认真考虑是否有办法消除嵌套循环
以下是一些有用的技巧:
第一种技术:将内部循环重构为方法。让方法返回是否中断外部循环。因此:
for(outer blah blah blah)
{
for(inner blah blah blah)
{
if (whatever)
{
goto leaveloop;
}
}
}
leaveloop:
...
变成
for(outer blah blah blah)
{
if (Inner(blah blah blah))
break;
}
...
bool Inner(blah blah blah)
{
for(inner blah blah blah)
{
if (whatever)
{
return true;
}
}
return false;
}
第二种技巧:如果循环没有副作用,使用LINQ
// fulfill the first unfulfilled order over $100
foreach(var customer in customers)
{
foreach(var order in customer.Orders)
{
if (!order.Filled && order.Total >= 100.00m)
{
Fill(order);
goto leaveloop;
}
}
}
leaveloop:
相反,写下:
var orders = from customer in customers
from order in customer.Orders;
where !order.Filled
where order.Total >= 100.00m
select order;
var orderToFill = orders.FirstOrDefault();
if (orderToFill != null) Fill(orderToFill);
无循环,因此无需中断
或者,正如configurator在注释中指出的,您可以用以下形式编写代码:
var orderToFill = customers
.SelectMany(customer=>customer.Orders)
.Where(order=>!order.Filled)
.Where(order=>order.Total >= 100.00m)
.FirstOrDefault();
if (orderToFill != null) Fill(orderToFill);
这个故事的寓意是:循环强调控制流,而牺牲了业务逻辑。与其试图将越来越复杂的控制流相互叠加,不如尝试重构代码,使业务逻辑清晰。如果要跳过该项,我建议使用continue
,如果要退出循环,建议使用break
。对于更深层的嵌套,请将其放入方法中并使用return
。我个人宁愿使用状态bool,也不愿使用goto
。宁可使用goto
作为最后手段。inti=0;
int i = 0;
while(i <= 10)
{
Debug.WriteLine(i);
i++;
for(int j = 0; j < 3 && i <= 5; j++)
{
//Whatever you want to do
}
}
while(i)匿名函数
你几乎总能找到匿名函数或lambda的内部循环,这里你可以看到函数曾经是一个内部循环,我不得不使用GoTo
private void CopyFormPropertiesAndValues()
{
MergeOperationsContext context = new MergeOperationsContext() { GroupRoot = _groupRoot, FormMerged = MergedItem };
// set up filter functions caller
var CheckFilters = (string key, string value) =>
{
foreach (var FieldFilter in MergeOperationsFieldFilters)
{
if (!FieldFilter(key, value, context))
return false;
}
return true;
};
// Copy values from form to FormMerged
foreach (var key in _form.ValueList.Keys)
{
var MyValue = _form.ValueList(key);
if (CheckFilters(key, MyValue))
MergedItem.ValueList(key) = MyValue;
}
}
手动搜索数据集中的多个项目时也会出现这种情况。遗憾的是,从清晰的角度来看,正确使用goto比布尔/标志更好,但这比任何一个都清楚,避免了同事的嘲笑
然而,对于高性能的情况,goto是合适的,但只有1%,让我们诚实地说…一如既往:我发现这篇有趣文章的可能副本-我本人从未在C#中使用过goto,但我喜欢这家伙的视角。它描述了我们对这些亵渎思想的反应,如(喘息)goto语句在C#中非常准确。@Dani除了重复别人说的“正确”之外,你还有什么理由吗?@Rob:我想这是一种风格的选择。你总是可以用全局变量编写整个程序,除了Main之外没有类和函数。语言支持它。从这个意义上说,它当然不是不适用的可接受的。什么样的东西对你来说是“可接受的”或“不可接受的”?不可接受的?从未见过有必要这样做,但“不可接受的”太多了。@Sjoerd-read@Rob,所以我们不同意。但这是问题的有效答案,而且有原因。因此:不需要否决投票。@Sjoerd你给出了一个替代的实现,而不是为什么它更好,或者为什么不应该使用goto的原因。叹气,我们又来了。对否决投票有什么解释吗,否决投票人?请参阅我的answe上的讨论r、 “不可接受”对某些人来说是一个不可接受的答案。try对我来说听起来太温和了。以我的经验,wha
private void CopyFormPropertiesAndValues()
{
MergeOperationsContext context = new MergeOperationsContext() { GroupRoot = _groupRoot, FormMerged = MergedItem };
// set up filter functions caller
var CheckFilters = (string key, string value) =>
{
foreach (var FieldFilter in MergeOperationsFieldFilters)
{
if (!FieldFilter(key, value, context))
return false;
}
return true;
};
// Copy values from form to FormMerged
foreach (var key in _form.ValueList.Keys)
{
var MyValue = _form.ValueList(key);
if (CheckFilters(key, MyValue))
MergedItem.ValueList(key) = MyValue;
}
}