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

Viewed 30115

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.

10 Answers

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);
  }
}

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

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

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

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.

ForEach is implemented in the concrete class List<T>

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.

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.

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

Related