ForEach, a simple but very useful extension method

This evening I was writing some code (Yay!) for an Xml based MEF catalog I am prototyping. I came across the need to invoke a set of methods on an IEnumerable<T> that was returned from a LINQ to XML query. Unfortunately no such animal exists on IEnumerable.

It took me < 5 mins to write this

   1: public static class IEnumerableUtils
   2: {
   3:       public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
   4:       {
   5:         foreach(T item in collection)
   6:           action(item);
   7:       }
   8: }

Any questions?

This entry was posted in LINQ, misc. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://geeks.ms/blogs/ohernandez Octavio Hernandez

    Glenn,

    This extension method has the potential problem that it may lead developers to think that they can universally use it in order to update each member of a collection. For instance, given

    class Person
    {
    public string Name { get; set; }
    public int Age { get; set; }
    public override string ToString()
    {
    return Name + “(” + Age + “)”;
    }
    }

    you could do

    List list1 = new List {
    new Person() { Name = “ann”, Age = 23 },
    new Person() { Name = “barbara”, Age = 28 },
    new Person() { Name = “celia”, Age = 27 },
    };

    list1.ForEach(
    p => { p.Age++; });

    and this will increment the age of each Person in the collection.

    But this “technique” will not work for collections of any value type, and not even of string, which is a reference type!

  • http://wekempf.spaces.live.com wekempf

    I posted on your blog as well, but the gist of my post is that to those who have used other functional languages, it is clear that ForEach should not be chainable.

  • http://gregbeech.com/blogs/tech/ Greg Beech

    I left a full response on my blog post (where wekempf also posted a comment). The essence is that not all LINQ operations are chainable or deferred, but all operations that are chainable are also deferred, and vice versa. As it isn’t clear whether ForEach should be chainable, it isn’t clear whether it should be deferred.

  • http://wekempf.spaces.live.com wekempf

    Both Yoshi Carroll in the comment above, and Greg Beech in his linked post comment that Linq uses deferred execution and chaining. That’s simply not true. Some parts of Linq follow this, but not all. Just one example is Average, which is neither chainable nor does deferred execution. I can’t begin to guess why ForEach was left out, but it seems obvious that’s not why.

  • http://gregbeech.com/blogs/tech/ Greg Beech

    My assumption as to why the Enumerable class doesn’t provide a ForEach extension method is because there are a number of valid implementations, using either deferred or immediate execution. I wrote more about this a couple of months back: http://gregbeech.com/blogs/tech/archive/2008/06/30/why-doesn-t-system-linq-enumerable-have-a-foreach-extension-method.aspx

  • http://weblogs.asp.net/zowens/ Zack Owens

    Any reason you didn’t check for nulls?

  • http://www.tavaresstudios.com Chris Tavares

    I suspect the reason that this didn’t exist before is that you can’t use it from VB. VB only support lambda expressions, while the foreach method requires a lambda *statement*.

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    @Kelly

    Sure, but to keep with how LINQ extensions were handled, it would have been added via an extension method to the interface ;)

  • http://www.codebetter.com/blogs/glenn.block/ Glenn Block

    @Bill

    I can see the value in, though I would have adifferent name then. foreach in fx by itself only yields if I add the yield statement.

    Glenn

  • Bill

    I like this as a better implementation:

    public IEnumerable ForEach(this IEnumerable collection, Action action) {
    foreach(var item in collection) {
    action(item);
    yield return item;
    }
    }

  • http://kleahy-technical.blogspot.com Kelly Leahy

    I think the reason ForEach wasn’t added to IEnumerable (not via extension methods, but to the interface itself) was that doing so would require reimplementation of this ‘algorithm’ by anyone who implements IEnumerable. That would be painful at best and error-prone at worst.

  • http://Bryan.ReynoldsLive.com Bryan Reynolds

    Inconsistencies. ugh.

  • http://kentb.blogspot.com/ Kent Boogaart

    Ugh, just realised how stupid my comment was. It’s exactly what you were talking about. Sleep.

    In summary, enumerating an enumerable seems like the perfect thing for System.Linq.Enumerable to do. And yet it doesn’t.

  • Yoshi Carroll

    I’ve been (over?)thinking about this for a while now and have currently settled on using ToList().Foreach() instead. What bothers me about the implementation you show is that it breaks the conventions of Linq extension methods in that it’s not chainable, and it’s not lazy. So, while it’s possible to do .Where().Select().Foreach(), its not possible to do .Where().Foreach().Select().

    This is obviously by design and it works as you needed it to but it feels a bit ambiguous to me. I tried to think of another name for it, something that would communicate the distinction, but nothing felt right.

    Using .ToList().Foreach() is more explicit in what the intention is, but it has an extra method in the chain, and it’s enumerating the collection twice, so I’m not much happier with it either.

    Am I just overworking this idea?

  • http://panteravb.com Chris

    Took me less than 5 seconds to google an existing solution :)

    http://davesquared.blogspot.com/2008/03/ienumerable-and-foreach.html

  • http://www.peterRitchie.com/blog Peter Ritchie

    I’ve often wondered why a ForEach wasn’t added for IEnumerable. It’s very handy on List

  • Calvin

    Beautiful. I’m a fan of anything that makes C# act more like Ruby.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    Ah! And don’t forget ForEach’s cousin, with an index:

    public static void Each(this IEnumerable items, Action action)
    {
    int i = 0;
    foreach (var item in items)
    {
    action(item, i++);
    }
    }

  • http://kentb.blogspot.com/ Kent Boogaart

    There’s also no equivalent on System.Linq.Enumerable, which has irked me on several occasions.

  • http://www.sidarok.com Sidar Ok
  • http://koder.wordpress.com/ Neil Barnwell

    Ahh, of course. He only has the IEnumerable interface and my example was getting ForEach from List.

    Gosh, I amaze myself with my own stupidity sometimes.

  • Łukasz Podolak

    No Neil, List is probably too much what he wants.

    I also was wondering why the ForEach method was put inside List and not IEnumerable ?

  • http://koder.wordpress.com/ Neil Barnwell

    I just wrote this in a Main method:

    List items = new List();
    items.Add(“Item 1″);
    items.Add(“Item 2″);
    items.Add(“Item 3″);

    items.ForEach(s => Console.WriteLine(s));

    Is this not what you want? I’m running VS 2008 on .NET 3.5.