Why is .ForEach() on IList<T> and not on IEnumerable<T>?

C#ListLinqC# 3.0Ienumerable

C# Problem Overview


> Possible Duplicate:
> Why is there not a ForEach extension method on the IEnumerable interface?

I've noticed when writing LINQ-y code that .ForEach() is a nice idiom to use. For example, here is a piece of code that takes the following inputs, and produces these outputs:

{ "One" } => "One"
{ "One", "Two" } => "One, Two"
{ "One", "Two", "Three", "Four" } => "One, Two, Three and Four";

And the code:

private string InsertCommasAttempt(IEnumerable<string> words)
{
    List<string> wordList = words.ToList();
    StringBuilder sb = new StringBuilder();
    var wordsAndSeparators = wordList.Select((string word, int pos) =>
        {
            if (pos == 0) return new { Word = word, Leading = string.Empty };
            if (pos == wordList.Count - 1) return new { Word = word, Leading = " and " };
            return new { Word = word, Leading = ", " };
        });

    wordsAndSeparators.ToList().ForEach(v => sb.Append(v.Leading).Append(v.Word));
    return sb.ToString();
}

Note the interjected .ToList() before the .ForEach() on the second to last line.

Why is it that .ForEach() isn't available as an extension method on IEnumerable<T>? With an example like this, it just seems weird.

C# Solutions


Solution 1 - C#

Because ForEach(Action) existed before IEnumerable<T> existed.

Since it was not added with the other extension methods, one can assume that the C# designers felt it was a bad design and prefer the foreach construct.


Edit:

If you want you can create your own extension method, it won't override the one for a List<T> but it will work for any other class which implements IEnumerable<T>.

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

Solution 2 - C#

According to Eric Lippert, this is mostly for philosophical reasons. You should read the whole post, but here's the gist as far as I'm concerned:

> I am philosophically opposed to > providing such a method, for two > reasons. > > The first reason is that doing so > violates the functional programming > principles that all the other sequence > operators are based upon. Clearly the > sole purpose of a call to this method > is to cause side effects. > > The purpose of an expression is to > compute a value, not to cause a side > effect. The purpose of a statement is > to cause a side effect. The call site > of this thing would look an awful lot > like an expression (though, > admittedly, since the method is > void-returning, the expression could > only be used in a “statement > expression” context.) > > It does not sit well with me to make > the one and only sequence operator > that is only useful for its side > effects. > > The second reason is that doing so > adds zero new representational power > to the language.

Solution 3 - C#

Because ForEach() on an IEnumerable is just a normal for each loop like this:

for each T item in MyEnumerable
{
    // Action<T> goes here
}

Solution 4 - C#

ForEach isn't on IList it's on List. You were using the concrete List in your example.

Solution 5 - C#

I am just guessing here , but putting foreach on IEnumerable would make operations on it to have side effects . None of the "available" extension methods cause side effects , putting an imperative method like foreach on there would muddy the api I guess . Also, foreach would initialize the lazy collection .

Personally I've been fending off the temptation to just add my own , just to keep side effect free functions separate from ones with side effects.

Solution 6 - C#

ForEach is implemented in the concrete class List<T>

Solution 7 - C#

Just a guess, but List can iterate over its items without creating an enumerator:

public void ForEach(Action<T> action)
{
    if (action == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    for (int i = 0; i < this._size; i++)
    {
        action(this._items[i]);
    }
}

This can lead to better performance. With IEnumerable, you don't have the option to use an ordinary for-loop.

Solution 8 - C#

LINQ follows the pull-model and all its (extension) methods should return IEnumerable<T>, except for ToList(). The ToList() is there to end the pull-chain.

ForEach() is from the push-model world.

You can still write your own extension method to do this, as pointed out by Samuel.

Solution 9 - C#

I honestly don't know for sure why the .ForEach(Action) isn't included on IEnumerable but, right, wrong or indifferent, that's the way it is...

I DID however want to highlight the performance issue mentioned in other comments. There is a performance hit based on how you loop over a collection. It is relatively minor but nevertheless, it certainly exists. Here is an incredibly fast and sloppy code snippet to show the relations... only takes a minute or so to run through.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Start Loop timing test: loading collection...");
        List<int> l = new List<int>();

        for (long i = 0; i < 60000000; i++)
        {
            l.Add(Convert.ToInt32(i));
        }

        Console.WriteLine("Collection loaded with {0} elements: start timings",l.Count());
        Console.WriteLine("\n<===============================================>\n");
        Console.WriteLine("foreach loop test starting...");

        DateTime start = DateTime.Now;

        //l.ForEach(x => l[x].ToString());

        foreach (int x in l)
            l[x].ToString();

        Console.WriteLine("foreach Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");
        Console.WriteLine("List.ForEach(x => x.action) loop test starting...");

        start = DateTime.Now;

        l.ForEach(x => l[x].ToString());

        Console.WriteLine("List.ForEach(x => x.action) Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");

        Console.WriteLine("for loop test starting...");

        start = DateTime.Now;
        int count = l.Count();
        for (int i = 0; i < count; i++)
        {
            l[i].ToString();
        }

        Console.WriteLine("for Loop Time for {0} elements = {1}", l.Count(), DateTime.Now - start);
        Console.WriteLine("\n<===============================================>\n");

        Console.WriteLine("\n\nPress Enter to continue...");
        Console.ReadLine();
    }

Don't get hung up on this too much though. Performance is the currency of application design but unless your application is experiencing an actual performance hit that is causing usability problems, focus on coding for maintainability and reuse since time is the currency of real life business projects...

Solution 10 - C#

It's called "Select" on IEnumerable<T> I am enlightened, thank you.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOlemaView Question on Stackoverflow
Solution 1 - C#SamuelView Answer on Stackoverflow
Solution 2 - C#Justin R.View Answer on Stackoverflow
Solution 3 - C#Joel CoehoornView Answer on Stackoverflow
Solution 4 - C#Joshua BeldenView Answer on Stackoverflow
Solution 5 - C#SuryaView Answer on Stackoverflow
Solution 6 - C#Chad GrantView Answer on Stackoverflow
Solution 7 - C#RauhotzView Answer on Stackoverflow
Solution 8 - C#tofi9View Answer on Stackoverflow
Solution 9 - C#AaronView Answer on Stackoverflow
Solution 10 - C#JP AliotoView Answer on Stackoverflow