Ну, goto
, но это ужасно, и не всегда возможно. Можно также поместить циклы в метод (или скоро-метод) и использование return
для выхода назад к основному коду.
// goto
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 100; j++)
{
goto Foo; // yeuck!
}
}
Foo:
Console.WriteLine("Hi");
по сравнению с:
// anon-method
Action work = delegate
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
return; // exits anon-method
}
}
};
work(); // execute anon-method
Console.WriteLine("Hi");
<час> Примечание, что в C# 7 мы должны получить "локальные функции", который (синтаксис tbd и т.д.) означает, он должен работать что-то как:
// local function (declared **inside** another method)
void Work()
{
for (int x = 0; x < 100; x++)
{
for (int y = 0; y < 100; y++)
{
return; // exits local function
}
}
};
Work(); // execute local function
Console.WriteLine("Hi");
Я думаю, если Вы не хотите сделать, "булева вещь" единственное решение состоит в том, чтобы на самом деле бросить. Который Вы, очевидно, не должны делать..!
Так как я увидел в первый раз break
в C несколько десятилетий назад, эта проблема досадила мне. Я надеялся, что некоторое улучшение языка будет иметь расширение для повреждения, который работал бы таким образом:
break; // our trusty friend, breaks out of current looping construct.
break 2; // breaks out of the current and it's parent looping construct.
break 3; // breaks out of 3 looping constructs.
break all; // totally decimates any looping constructs in force.
Я видел много примеров, которые используют "повреждение", но ни один, что "продолжает" использование.
Это все еще потребовало бы какого-то флага во внутреннем цикле:
while( some_condition )
{
// outer loop stuff
...
bool get_out = false;
for(...)
{
// inner loop stuff
...
get_out = true;
break;
}
if( get_out )
{
some_condition=false;
continue;
}
// more out loop stuff
...
}
Вы попросили комбинацию быстрых, хороших, нет смысла в булевской переменной, нет смысла goto, и C#. Вы исключили все возможные способы сделать то, что Вы хотите.
самый быстрый и наименее ужасный путь состоит в том, чтобы использовать goto.
фактор в функцию/метод и использует ранний возврат или перестраивает Ваши циклы в выражение while. goto/exceptions/whatever являются, конечно, не соответствующими здесь.
def do_until_equal():
foreach a:
foreach b:
if a==b: return
Действительно ли возможно осуществить рефакторинг вложенный для цикла в закрытый метод? Тем путем Вы могли просто 'возвратиться' из метода для выхода из цикла.
Не заключайте мне в кавычки на этом, но Вы могли использовать goto, как предложено в MSDN. Существуют другие решения, как включая флаг, который проверяется в каждом повторении обоих циклов. Наконец Вы могли использовать исключение в качестве действительно тяжелого решения Вашей проблемы.
GOTO:
for ( int i = 0; i < 10; ++i ) {
for ( int j = 0; j < 10; ++j ) {
// code
if ( break_condition ) goto End;
// more code
}
}
End: ;
Условие:
bool exit = false;
for ( int i = 0; i < 10 && !exit; ++i ) {
for ( int j = 0; j < 10 && !exit; ++j ) {
// code
if ( break_condition ) {
exit = true;
break; // or continue
}
// more code
}
}
Исключение:
try {
for ( int i = 0; i < 10 && !exit; ++i ) {
for ( int j = 0; j < 10 && !exit; ++j ) {
// code
if ( break_condition ) {
throw new Exception()
}
// more code
}
}
catch ( Exception e ) {}
Используйте подходящую защиту во внешнем цикле. Установите защиту во внутреннем цикле перед повреждением.
bool exitedInner = false;
for (int i = 0; i < N && !exitedInner; ++i) {
.... some outer loop stuff
for (int j = 0; j < M; ++j) {
if (sometest) {
exitedInner = true;
break;
}
}
if (!exitedInner) {
... more outer loop stuff
}
}
Или еще лучше, абстрагируйте внутренний цикл в метод и выйдите из внешнего цикла, когда это возвратит false.
for (int i = 0; i < N; ++i) {
.... some outer loop stuff
if (!doInner(i, N, M)) {
break;
}
... more outer loop stuff
}
Это решение не относится к C#
За людей, которые нашли этот вопрос через другие языки, JavaScript, Java, и D позволяет маркированные повреждения и продолжается :
outer: while(fn1())
{
while(fn2())
{
if(fn3()) continue outer;
if(fn4()) break outer;
}
}
Адаптация C# подхода часто использовала в C - установленное значение переменной внешнего цикла за пределами условий цикла (т.е. для цикла с помощью международной переменной INT_MAX -1
часто хороший выбор):
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 100; j++)
{
if (exit_condition)
{
// cause the outer loop to break:
// use i = INT_MAX - 1; otherwise i++ == INT_MIN < 100 and loop will continue
i = int.MaxValue - 1;
Console.WriteLine("Hi");
// break the inner loop
break;
}
}
// if you have code in outer loop it will execute after break from inner loop
}
, Поскольку в примечании в коде говорится break
, волшебно не перейдет к следующему повторению внешнего цикла - поэтому, если у Вас будет код за пределами внутреннего цикла, этот подход требует большего количества проверок. Рассмотрите другие решения в таком случае.
Этот подход работает с for
и while
циклы, но не работает на foreach
. В случае foreach
у Вас не будет доступа кода к скрытому перечислителю, таким образом, Вы не сможете изменить его (и даже если Вы могли IEnumerator
не иметь некоторого метода "MoveToEnd").
Список благодарностей авторам встроенных комментариев:
i = INT_MAX - 1
предложение [1 112] Meta for
/ foreach
комментарий [1 113] ygoe.
Надлежащий IntMax
[1 114] комментарий jmbpiano
о коде после внутреннего цикла [1 115] blizpasta