Thursday, 20 March 2008

IEnumerable<T> and ForEach()

Why is there no ForEach() extension method defined for IEnumerable<T> in System.Linq.Enumerable for .NET 3.5? There is a ForEach() on Array and List<T>, but not for IEnumerable<T> which would seem a fairly natural place for it.

public static class Extensions {
  public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
    foreach (var item in source) {
      action(item);
    }
  }
}
Update 2008-07-17: An anonymous commenter left a great point about returning source after finishing the iteration instead of using a void method. This breaks the standard signature used by the Array and List<T> classes, but fits in nicely with the general approach used in the System.Linq.Enumerable extension methods, and lets you do LINQy method chaining.

For some reason, when I'm in LINQy mode, my natural reaction is to try ForEach() over foreach, and I'm always a bit surprised when it doesn't work for IEnumerable<T>:

//Lambda goodness:
parameters.ForEach(parameter => doSomethingTo(parameter));

//Old stylz:
foreach (var parameter in parameters) {
  doSomethingTo(parameter);
}

Bit nit-picky I know, but I noticed Daniel Cazzulino made the same observation:

"I added a ForEach extension method to IEnumerable. How come it's missing in .NET 3.5? :S"

So at least I'm not completely alone on this :-) Anyone else wonder about this?


Share/Save/Bookmark

8 comments:

gugo said...

I was searching for it just now.
Incredible.

I need to convert to List before using the ForEach.

I tried to add a ForEach a extension, but i cannot write it without the usage of the
foreach(var v in IEnum...)
So again is like returning to a List

:(

David said...

@gugo,
I'm not sure exactly what problem you are having getting the ForEach extension to work. Feel free to post some code or email me if you would like any clarification.
Regards,
David

Yann Trevin said...

Indeed, it's seems incredible to me they just forgot that feature. Do you know if there is any good reason behind, or do you believe it's really an omission?

David said...

Hi @Yann,
I really have no idea why it's not in there. I can't see any downsides for including it.

At least it's easy to add thanks to extension methods :)

Anonymous said...

I am surprised that the ForEach() was left off of the IEnumerable<T> interface as well. Thanks for bringing up this topic. As a small variation on your implementation of ForEach() I return the "source" extension argument after the loop has executed since I often do things like IEnumerable<T>.While(item => item.Property == 1).ForEach(item => item.Property += 1).Select(item => item.Property == 2);

Folks may have other opinions, but for me it keeps the method result chain consistent.

David said...

@Anonymous,
Great point about enabling method chaining.

I was originally aiming for the same signature as for Array.ForEach<T> and List<T>.ForEach, but I like your way better. It's more consistent with most of the extension methods in System.Linq.Enumerable.

Anonymous said...

This doesn't work with value types... if you are trying to change something on the value type it doesn't work.

David said...

Anonymous,

Not sure what you mean about not working for value types?

You can't use foreach to update an array of value types (say, int[]) because you would only be operating on a local copy of the value. In fact, C# prevents this with a CS1656 error.

So in this regard the .ForEach() extension method pretty much works as expected. (As you can see, it is just syntactic sugar over foreach anyway.)

Regards,
David