CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Glenn Block

Another ALT.NET guy at Microsoft

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?


Published Aug 19 2008, 12:46 AM by Glenn Block
Filed under: ,

Comments

Neil Barnwell said:

I just wrote this in a Main method:

           List<string> items = new List<string>();

           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.

# August 19, 2008 4:44 AM

Łukasz Podolak said:

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

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

# August 19, 2008 5:24 AM

Neil Barnwell said:

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

Gosh, I amaze myself with my own stupidity sometimes.

# August 19, 2008 5:57 AM

Sidar Ok said:

# August 19, 2008 7:50 AM

Kent Boogaart said:

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

# August 19, 2008 7:50 AM

Jimmy Bogard said:

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

public static void Each<T>(this IEnumerable<T> items, Action<T, int> action)

{

int i = 0;

foreach (var item in items)

{

action(item, i++);

}

}

# August 19, 2008 8:23 AM

Calvin said:

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

# August 19, 2008 9:08 AM

Peter Ritchie said:

I've often wondered why a ForEach wasn't added for IEnumerable<T>.  It's very handy on List<T>...

# August 19, 2008 9:12 AM

Chris said:

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

davesquared.blogspot.com/.../ienumerable-and-foreach.html

# August 19, 2008 9:30 AM

Yoshi Carroll said:

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?

# August 19, 2008 9:41 AM

Kent Boogaart said:

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.

# August 19, 2008 11:44 AM

Bryan Reynolds said:

Inconsistencies. ugh.

# August 19, 2008 12:01 PM

Kelly Leahy said:

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

# August 19, 2008 12:47 PM

Bill said:

I like this as a better implementation:

public IEnumerable<TSource> ForEach(this IEnumerable<TSource> collection, Action<TSource> action) {

   foreach(var item in collection) {

       action(item);

       yield return item;

   }

}

# August 19, 2008 3:18 PM

Glenn Block said:

@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

# August 19, 2008 3:37 PM

Glenn Block said:

@Kelly

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

# August 19, 2008 3:38 PM

Chris Tavares said:

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*.

# August 19, 2008 6:46 PM

Zack Owens said:

Any reason you didn't check for nulls?

# August 21, 2008 3:48 PM

Greg Beech said:

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: gregbeech.com/.../why-doesn-t-system-linq-enumerable-have-a-foreach-extension-method.aspx

# August 23, 2008 11:35 AM

wekempf said:

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.

# August 25, 2008 4:03 PM

Greg Beech said:

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.

# August 26, 2008 7:02 AM

wekempf said:

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.

# August 26, 2008 9:19 AM

Pensando en asíncrono said:

Últimamente ya no escribo nada, estoy totalmente inmerso en el mundo LINQ con el C# 3.0 y LINQ de Octavio

# September 11, 2008 6:33 PM

vtortola said:

Últimamente ya no escribo nada, estoy totalmente inmerso en el mundo LINQ con el C# 3.0 y LINQ de Octavio

# September 11, 2008 6:33 PM

Octavio Hernandez said:

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!
# September 12, 2008 6:33 AM

Sobre C#, LINQ y algo más... said:

Recientemente, Valeriano Tórtola publicó un excelente post en el que mostraba la utilización de un método

# September 14, 2008 8:22 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Glenn Block

Glenn is a PM for the new Managed Extensibility Framework in .NET 4.0. Prior to Microsoft, he worked for 10 years in various startups and ISVs wearing many different hats all related to developing software. Glenn has been writing code practically since the time he learned how to ride a bicycle. When he's not writing code, he's continuously improving on ways to build better software. Glenn is a geek at heart and spends a good portion of the rest of this time spreading that geekdom through conferences, and the community through groups such as ALT.NET. When he's not working and playing with technology, he spends his time with his wife and four year old daughter either at their Seattle apartment or at one of the local coffee shops. Check out Devlicio.us!

Our Sponsors