2016-03-02 2 views
7

как сломать сначала для каждого цикла из второго вложенного для каждого цикла в C#, я хочу проверить некоторые условия во втором для каждого цикла, а затем попытаться сломать родительский для каждого циклакак разбить первый цикл foreach из второго вложенного цикла foreach в C#

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

ответ

3

Вы можете попробовать использовать return так:

foreach(//do some stuff) 
    foreach(//do some stuff) 
     if(//check some condition) 
      return; 
+1

Это то, что мне нужно –

+3

Хотя это может служить целям OP, 'return' делает больше, чем вырывается из циклов - он вырывается из функции, содержащей петли! И справедливости ради других, предлагающих ответы, нигде OP не упоминает, что эти петли являются частью функции, которая возвращает значение, которое они зацикливали, чтобы получить. – rskar

4

Быстрый ответ:

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 ...

Нарушения SESE являются нарушением принципа Single Single Single Exit. Это довольно легко исправить, используя дополнительное условие:

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. Вы можете использовать goto.
  2. Вы можете использовать дополнительный флаг.

Вариант 1 будет скомпилирован в поле, имеющее память. Память «провалена» в том смысле, что компиляторы сделают все возможное, чтобы потреблять как можно меньше памяти, предпочтительнее в регистрах. Отсюда и ваша работа. Таким образом, компилятор попытается устранить флаг.

Чтобы сделать это, ваш компилятор выполнит тонну анализа потока и другие вещи, , пытаясь определить, что на самом деле есть два пути кода: тот, когда установлен флаг, а другой, если он не.

Теперь, если вам повезет, у компилятора будет свой «ага» момент и сменит ваш код с (2) на простой GOTO, и в этом случае небо все еще будет синим, и все будут счастливы.

Однако, если вам не повезло (и есть много практических причин для этого), он не обнаружит этого из анализа потока и не создаст GOTO. Поскольку ваш флаг используется во внутреннем цикле, он может даже выделить для этого регистр, что может быть наихудшим сценарием.

Если бы вы использовали goto в первую очередь, это не нужно для всего этого. Вы просто даете компилятору правильное решение. Просто.

У вас есть более подробная информация о том, как это делает компилятор?

Да, посмотрите на это 2 часа видео Чандлер, который объясняет много о том, как работают компиляторы: https://www.youtube.com/watch?v=FnGCDLhaxKU

-updated- Очевидно, что некоторые люди misintepreted мою историю, как было указано на @Groo. Я внес некоторые коррективы, чтобы уточнить, что я хотел сказать.

+4

https://xkcd.com/292/ – Loofer

+1

@Loofer: однажды в голубой луне вы позволяете себе использовать 'goto', особенно если вы не можете поставить' return'. –

+0

@ Локальные петли компилируются в IL GOTO и LABEL. Просто не делайте это привычкой, если у вас есть альтернатива. – atlaste

1
bool doBreak = false; 
foreach(//do some stuff) 
{ 
    foreach(//do some stuff) 
    { 
     doBreak = <check some condition>; 
     if(doBreak) break; 
    } 
    if(doBreak) break; 
} 
4

Вы можете сделать это с помощью 'флаг'

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

Вы можете использовать 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; 
    } 
} 
2

Если вы не можете 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 
      } 
    } 
} 
+0

«Читаемый» в глазах смотрящего, я думаю. :) – Groo

Смежные вопросы