25

Since ForEach() method loop through all list members, Why can't I use a break/continue clause while I can use them inside a normal foreach loop

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

Error:

"No enclosing loop out of which to break or continue"

Rami Alshareef
  • 7,015
  • 12
  • 47
  • 75
  • A well written ForEach extension should allow you to return false if you want it to break. But I can't say for sure since I don't know where you got your foreach. If you wrote it yourself that may be a good option. – Tesserex Dec 14 '10 at 14:18
  • Looks like you want the TakeWhile function http://msdn.microsoft.com/en-us/library/bb534804%28v=VS.90%29.aspx – Juliet Dec 15 '10 at 15:56
  • I found a better answer here: http://stackoverflow.com/questions/3145563/list-foreach-break – CS Smit Apr 14 '15 at 09:59

9 Answers9

24

return will act as continue in ForEach.

Example:

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

Prints 1, 2, 4.

3 - skipped.

TarasB
  • 2,407
  • 1
  • 24
  • 32
24

Because ForEach is a method and not a regular foreach loop. The ForEach method is there for simple tasks, if you need to break or continue just iterate over lstTemp with a regular foreach loop.

Usually, ForEach is implemented like this:

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

As it is a normal method call, action doesn't know anything about the enclosing foreach, thus you can't break.

Femaref
  • 60,705
  • 7
  • 138
  • 176
17

Presumably because you're using a lambda and the contents of the lambda are ignorant to the fact that it's being used inside a loop.

Antony Woods
  • 4,415
  • 3
  • 26
  • 47
9

rather than using a break, perform a filter first like this (it may not be the exact filter you need, but illustrates the point)

lstTemp.Where(i => i!= 3).ForEach(i=> // do sth);
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
  • -1 Not the samething. your code will run for every i != 3. The code presented will run until i == 3. – Sergio Dec 14 '10 at 14:19
  • This seems the best way for 'continue'. Besides we can just write 'return' for 'break'. – Nigiri Jun 12 '13 at 02:56
5

The way I'd explain it is this: ForEach is a method, not a language feature. The C# foreach construct is a feature of the language within which the other language constructs break and continue are permitted.

I would also point out (not trying to judge, just making an observation) that this is a good example of why some developers object to the use of a ForEach method: it doesn't really save typing in this simple case, it requires one more redirection than necessary, and it doesn't have all the functionality of foreach anyway.

In my opinion the main scenario in which a ForEach method makes sense is as an extension on IEnumerable<T>--to put at the end of a chain of method calls. It seems (to me) a bit strange that they added it to List<T>.

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
4

Because ForEach is a method and not a regular foreach loop is need iterate over lstTemp with a regular foreach loop in case break, but in case continue use return inside the ForEach method.

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

Output: 1, 2, 4

LeoLana
  • 49
  • 1
  • 7
4

To iterate only part of the items and emulate the break perfectly, you can use FirstOrDefault:

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

   //do stuff

   return false;
 }
);

For list with 100000 items, if the 10th item is 3 it will iterate only 10 times, using the Where solution will work, but iterate the whole list first.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • 1
    The `Where` method does not iterate the collection, see: deferred execution. – James Gregory Dec 14 '10 at 14:55
  • @James maybe *iterate* isn't the right word.. but to find all matching items, somewhere somehow all items must be checked, isn't it? – Shadow The GPT Wizard Dec 14 '10 at 15:40
  • 1
    Have a read of how the `yield` keyword works, because that's how LINQ queries operate. It's too long to explain here, but no, not all the items must be checked; only as many items as are requested by the call-chain will be checked. Exactly the same as your `FirstOrDefault`, which will iterate until it hits a match. – James Gregory Dec 14 '10 at 16:59
2

break and continue are C# language keywords that require compiler support. ForEach, to the C# compiler, is just a method.

Mattias S
  • 4,748
  • 2
  • 17
  • 18
0

Because you delegate an action for each item in the list.

Ralf de Kleine
  • 11,464
  • 5
  • 45
  • 87