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
 

4 Responses to “ForEach method on IEnumerable”

  1. Isabelle Says:

    Just dropping by.Btw, you website have great content!

    ______________________________
    Unlimited Public Records Searches!

  2. […] have to use .ToList() just to be able to ForEach() an IEnumerable of T. This blog article shows a cool extension method that adds ForEach to IEnumerable of T. I added the extension method presented to my aresenal today. Leave a […]

  3. […] You may think three is almost no difference if you add an extension method ForEach to IEnumerable then use this call against use foreach kwyword. Unfortunitely you're incorrect. ForEach may have the singature like this: void ForEach<T>(Action<T>). Because ForEach takes parameter that is of type Action<T>, and actually Action<T> is a lambda expression, each lambda experssion can be convert either to anonymous delegates or Expression Tree according to the executive context, thus the ForEach method call may be translated to a specific statement or even database command when you have a ForEach extension method defined on IEnumerable<T> and apply this call on the IQueryable<T> instances or Linq to Sql objects. when call ForEach() on objects that have a valid Linq Provider, the method call will not actually be performed, instead, the meaning of this call will be translated into statements that recognized by the attached Linq Provider on this type. As a result, you may get incorrect outputs when call ForEach() over objects in different level of its hierarchy trees. If you define ForEach method on the base type for all Linq enabled objects (actually it is IEnumerable<T>). it may override the behavior of the same method on the derived types. For more information, see this blog post: https://ppetrov.wordpress.com/2009/01/22/foreach-method-on-ienumerable/ […]

  4. Jasper Stein Says:

    Hi,

    You said: “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”. But the semantic difference is not little at all! You’re doing two completely different things. If SlowMethod were called PayTaxes you’ll easily see the difference: in the first case, everyone pays taxes, and then millionaires are selected; in the second case, only the rich pay taxes.

    Since the semantics are so widely different I’d say you can’t talk about “this possible issue” since there is no issue here. It just comes down to knowing what you are doing when facing the ‘choice’ between these two ‘variants’


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s