4

Say I have a class:

public class MyClass
{
   ...
}

and a webservice method that returns an IEnumerable<MyClass>

The consumer of the webservice defines some method:

public void DoSomething(MyClass myClass)
{
   ...
}

Now, the consumer can call DoSomething on the result of the webservice method in two ways:

var result = // web service call

foreach(var myClass in result)
{
   DoSomething(myClass);
}

or:

var result = // web service call

result.ToList().ForEach(DoSomething);

Needless to say I much prefer the second way since it is much shorter and more expressive (once you get used to the syntax, which I have).

Now, the web service method only exposes an IEnumerable<MyClass>, but it actually returns a List<MyClass> which (AFAIK) means that the actual serialized object is still a List<T>. However, I have found (using reflector) that the Linq method ToList() makes a copy of all the objects in the IEnumerable<T> regardless of the actual runtime type (in my opinion, it could just have casted the argument to a List<T> if it already was one).

This obviously has some performance overhead, especially for large list (or lists of large objects).

So what can I do to overcome this problem, and why is there no ForEach method in Linq?

By the way, his question is vaguely related to this one.

Community
  • 1
  • 1
Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
  • `ToList()` does not make a copy of the objects unless they are value type. Instead, it creates a list with the same references, which allows a modification of the original list when the loop is still active (in some situation you may want this). It also allows the use of a variable delegate, in case the `DoSomething` action depends on something else or is an argument, and that is probably the case where `ForEach` makes sense - although you could do without. – RedGlyph Feb 21 '10 at 13:12

6 Answers6

5

You can write an extension method but there are good reasons why ForEach is not implemented on IEnumerable<T>. The second example

result.ToList().ForEach(DoSomething);

copies the IEnumerable into a List (unless it's already a List, I assume) so you're better off just iterating the IEnumerable with good old foreach(var r in result) {}.

Addendum:

For me, the key point of Eric Lippert's article is that adding ForEach has no benefit and adds some potential pitfalls:

The second reason is that doing so adds zero new representational power to the language. Doing this lets you rewrite this perfectly clear code:

foreach(Foo foo in foos){ statement involving foo; }

into this code:

foos.ForEach((Foo foo)=>{ statement involving foo; });

which uses almost exactly the same characters in slightly different order. And yet the second version is harder to understand, harder to debug, and introduces closure semantics, thereby potentially changing object lifetimes in subtle ways.

Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
  • 1
    +1 for linking to Eric Lippert's definitive post on why there is no ForEach in Linq – Gabe Moothart Feb 19 '10 at 15:35
  • That is correct, LINQ was designed for querying, not for iteration – sidney.andrews Feb 19 '10 at 15:39
  • I agree with the Eric's analysis of his example, but I think he neglects this: `foos.ForEach(SomeMethod)`. There are no closure semantics to speak of, and in my opinion it's actually easier to read and more concise than a `foreach` loop when all you want to do is call a method for each item in a list. Because of the clear benefit and lack of significant drawbacks, I went ahead and implemented my own extension method, and I'll never give it up! – Joel Mueller Feb 19 '10 at 23:55
5

I would prefer this:-

foreach (var item in result.ToList())
{
   DoSomething(item);
}

Its a much clearer idiom, it says collect a list of stuff together then do something important that may change the state of the application. Its old school but it works and is actually more understandable to a wider audience.

AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
  • I agree with the foreach but why convert to a List if it's already IEnumerable? – Jamie Ide Feb 19 '10 at 15:48
  • @Jamie: The `ToList` is there because its in the original question. There are times when that is necessary. If for example the `DoSomething` represents an operation that removes items from a collection that is the ultimate source of the `IEnumerable` then you'd likely get an exception if you don't include the `ToList`. Of course if you are happy that `DoSomething` isn't going to do that then most likely it isn't necessary. – AnthonyWJones Feb 19 '10 at 16:56
  • You can also put a breakpoint on the `ForEach` delegate parameter, so debugging is as easy in either case. – RedGlyph Feb 21 '10 at 12:59
  • @RedGlyph: Good point, I've removed Brian's edit of my answer. Am I off message to be slightly irritated with someone adding content like that to my answer? – AnthonyWJones Feb 21 '10 at 13:17
4

I use 2 methods. One iterates the list, one works with lazy eval. I use them as the situation defines.

    public static IEnumerable<T> ForEachChained<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
        {
            action(item);
            yield return item;
        }
    }

    public static IEnumerable<T> ForEachImmediate<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
        {
            action(item);
        }
        return source;
    }
TheSoftwareJedi
  • 34,421
  • 21
  • 109
  • 151
2

You can write your own extension method for IEnumerable<T> like so:

    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
    {
        foreach (T t in enumerable)
            action(t);
    } 

Such a method is not present in Linq, because Linq is basically meant for queries, not for simple iterations.

Also, note that when using an actual List<T> instance, the extension method will not be called because instance methods have precedence over extension methods when they share signature.

The following code, for example, would not invoke the extension method:

 var l = new List<MyClass>();
 l.Add(new MyClass());
 l.ForEach(DoSomething);

Whereas the following would:

IEnumerable<MyClass> l = new List<MyClass>(new []{new MyClass()});
l.ForEach(DoSomething);  
Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
  • 2
    Honestly, I really dislike this. It's not wrong, so I'm not going to downvote it, but you're conflating functional (closure) and imperative semantics here and it can easily lead to unexpected, hard-to-debug problems or at best poor readability. – Aaronaught Feb 19 '10 at 15:40
1

You can write your own extension method ToList(this List theList){return theList;} and then avoid the overhead. Since your extension method is the most specific one it will be called, not the one on IEnumerable

AndreasKnudsen
  • 3,453
  • 5
  • 28
  • 33
-2

If you decide to do this via an extension method, I'd call it ForAll instead of ForEach. This in order to use the same syntax as the Parallel Extensions in .NET 4.0 use:

var result = // web service call
result.AsParallel().ForAll(DoSomething);
CodingInsomnia
  • 1,843
  • 2
  • 15
  • 19
  • Why call it `ForAll`, introducing confusion with the parallelized version, when there's already an existing Framework method `ForEach` with this exact semantics (just a different type)? – Pavel Minaev Feb 19 '10 at 17:06