Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<T>.ForEach vs. custom IEnumerable<T> extension

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.

like image 369
Klaus Byskov Pedersen Avatar asked Dec 08 '22 04:12

Klaus Byskov Pedersen


1 Answers

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.

like image 156
Jamie Ide Avatar answered Dec 10 '22 03:12

Jamie Ide