ForEach (): почему нельзя использовать break / continue внутри

поскольку метод ForEach() проходит через все члены списка, почему нельзя использовать перерыв/продолжение предложение, пока я могу использовать их внутри обычного цикла foreach

lstTemp.ForEach(i=>
 {
   if (i == 3)
   break;
   //do sth
 }
);

ошибка:

" нет замкнутого цикла, из которого break или continue"

11 ответов


, потому что ForEach - Это метод, а не обычный foreach петли. The ForEach метод существует для простых задач, Если вам нужно сломать или продолжить, просто повторите lstTemp обычный foreach петли.

как правило, ForEach реализован следующим образом:

public static ForEach<T>(this IEnumerable<T> input, Action<T> action)
{
  foreach(var i in input)
    action(i);
}

поскольку это обычный вызов метода,action ничего не знает о вложении foreach, таким образом, вы не можете сломать.


предположительно, потому что вы используете лямбду, а содержимое лямбды не знает о том, что оно используется внутри цикла.


вместо того, чтобы использовать перерыв, сначала выполните фильтр (это может быть не тот фильтр, который вам нужен, Но иллюстрирует точку)

lstTemp.Where(i => i!= 3).ForEach(i=> // do sth);

для итерации только части элементов и эмуляции перерыва отлично, вы можете использовать FirstOrDefault:

lstTemp.FirstOrDefault(i=>
 {
   if (i == 3)
       return true;

   //do stuff

   return false;
 }
);

для списка со 100000 элементами, Если 10-й элемент равен 3, он будет повторяться только 10 раз, используя Where решение будет работать,но сначала повторите весь список.


Я бы объяснил это так:ForEach Это метод, а не языка. C# foreach construct является особенностью языка, в рамках которого другой язык строит break и есть.

Я бы также указал (не пытаясь судить, просто делая замечание), что это хороший пример того, почему некоторые разработчики возражают против использования ForEach метод: он действительно не сохраняет ввод в этом простом случае, это требуется еще одно перенаправление, чем необходимо, и оно не имеет всей функциональности foreach в любом случае.

на мой взгляд основной сценарий, в котором ForEach метод имеет смысл как расширение на IEnumerable<T>--поставить в конце цепочки вызовов методов. Мне кажется (мне) немного странным, что они добавили его в List<T>.


return будет действовать как continue на ForEach.

пример:

var list = new List<int>() {1, 2, 3, 4};
list.ForEach(i => 
    {
        if (i == 3)
            return;
        Console.WriteLine(i);
    }
);

печать 1, 2, 4.

3 - пропущен.


break и continue-ключевые слова языка C#, требующие поддержки компилятора. ForEach для компилятора C# - это просто метод.


поскольку ForEach является методом, а не регулярным циклом foreach, необходимо перебирать lstTemp с регулярным циклом foreach в случае разрыва, но в случае продолжения использования return внутри метода ForEach.

var lstTemp = new List<int>() {1, 2, 3, 4};
lstTemp.ForEach(i=>
{
     if (i == 3) return;
     //do sth
     Console.WriteLine(i);
});

выход: 1, 2, 4


потому что вы делегируете действие для каждого элемента в списке.


вы можете написать метод расширения "ForEachWhile", который принимает Function<T, bool> и останавливается при false.


я использовал его

        list.ForEach((item) =>
        {
            if( isBreak == false ) do
            {
                if (isContinue)
                    break;

                // TODO
            } while (false); }
        });