LINQ equivalent of foreach for IEnumerable

LINQ equivalent of foreach for IEnumerable

There is no ForEach extension for IEnumerable; only for List<T>. So you could do

items.ToList().ForEach(i => i.DoStuff());

Alternatively, write your own ForEach extension method:

public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
    foreach(T item in enumeration)
    {
        action(item);
    }
}

Fredrik has provided the fix, but it may be worth considering why this isnt in the framework to start with. I believe the idea is that the LINQ query operators should be side-effect-free, fitting in with a reasonably functional way of looking at the world. Clearly ForEach is exactly the opposite – a purely side-effect-based construct.

Thats not to say this is a bad thing to do – just thinking about the philosophical reasons behind the decision.

LINQ equivalent of foreach for IEnumerable

Update 7/17/2012: Apparently as of C# 5.0, the behavior of foreach described below has been changed and the use of a foreach iteration variable in a nested lambda expression no longer produces unexpected results. This answer does not apply to C# ≥ 5.0.

@John Skeet and everyone who prefers the foreach keyword.

The problem with foreach in C# prior to 5.0, is that it is inconsistent with how the equivalent for comprehension works in other languages, and with how I would expect it to work (personal opinion stated here only because others have mentioned their opinion regarding readability). See all of the questions concerning Access to modified closure
as well as Closing over the loop variable considered harmful. This is only harmful because of the way foreach is implemented in C#.

Take the following examples using the functionally equivalent extension method to that in @Fredrik Kalseths answer.

public static class Enumerables
{
    public static void ForEach<T>(this IEnumerable<T> @this, Action<T> action)
    {
        foreach (T item in @this)
        {
            action(item);
        }
    }
}

Apologies for the overly contrived example. Im only using Observable because its not entirely far fetched to do something like this. Obviously there are better ways to create this observable, I am only attempting to demonstrate a point. Typically the code subscribed to the observable is executed asynchronously and potentially in another thread. If using foreach, this could produce very strange and potentially non-deterministic results.

The following test using ForEach extension method passes:

[Test]
public void ForEachExtensionWin()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                values.ForEach(value => 
                                    source.OnNext(() => value));

                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Win
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

The following fails with the error:

Expected: equivalent to < 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 >
But was: < 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 >

[Test]
public void ForEachKeywordFail()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                foreach (var value in values)
                                {
                                    //If you have resharper, notice the warning
                                    source.OnNext(() => value);
                                }
                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Fail
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

Leave a Reply

Your email address will not be published.