Peter Petrov’s Weblog

var me = from practice in programming where practice.IsBestPractice && practice.UseLambda select practice.OptimalPerformance;

ForEach method on IEnumerable January 22, 2009

Filed under: .NET Framework,C#,Extension methods — ppetrov @ 5:37 pm
Tags: , ,

I’ve noticed that when I use IEnumerable<T> very often I have a construction like this

.ToList().ForEach(x=> ...)

in my code. I’ve thinked about it and I’ve realized that ToList() will create (probably) a large list just to iterrate over it and perform some action. That’s just because IEnumerable<T> doesn’t have ForEach method. Using an extension method I’m able to fill this gap. So here’s the ForEach method on IEnumerable<T> :

public static void ForEach<T>(this IEnumerable<T> values, Action<T> action)
{
    foreach (var v in values)
    {
        action(v);
    }
}

It’s possible to return the values reference to allow method chaining  but personally I think the foreach must be the last thing to perform, otherwise it will lead you to a bad practice. Let me explain what I mean. Imagine we have this Person class and a method that returns all Persons.

public static IEnumerable<Person> GetAllPersons()
{
    // ...
    yield break;
}
public class Person
{
    public long Fortune { get; private set; }

    public void SlowMethod()
    {
        Thread.Sleep(1000);
        // ...
    }
}

Take a look a the fowling two methods that retrieves all rich persons

var richPersonsSlow = GetAllPersons().ForEach(p => p.SlowMethod()).Where(p => p.Fortune > 1000000);
var richPersonsFast = GetAllPersons().Where(p => p.Fortune > 1000000).ForEach(p => p.SlowMethod());

Take this scenario : we have 3600 persons and only one have more then one million.

The first line will take an hour to return the millionaire.

The second line will take only one second to return the millionaire because p.SlowMethod will be called only on the millionaire.

There’s a little semantic difference in the example but I think you get the point. Using the ForEach returning void eliminates this possible issue.

I hope the BCL Team will include this method (not necessarly my implementation) in C# 4.0 .

Advertisements