Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 721
Olema Avatar asked Apr 28 '09 22:04

Olema


People also ask

Why to use IEnumerable instead of List?

We aren't forcing the caller to convert their data structure to a List unnecessarily. So it isn't that IEnumerable<T> is more efficient than list in a "performance" or "runtime" aspect. It's that IEnumerable<T> is a more efficient design construct because it's a more specific indication of what your design requires.

Why is foreach loop read only?

That is because foreach is meant to iterate over a container, making sure each item is visited exactly once, without changing the container, to avoid nasty side effects.

When should I use IEnumerable in C#?

IEnumerable interface is used when we want to iterate among our classes using a foreach loop. The IEnumerable interface has one method, GetEnumerator, that returns an IEnumerator interface that helps us to iterate among the class using the foreach loop.

Does List implement IEnumerable in C#?

List implements IEnumerable, but represents the entire collection in memory. LINQ expressions return an enumeration, and by default the expression executes when you iterate through it using a foreach, but you can force it to iterate sooner using .


4 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);
  }
}
like image 172
Samuel Avatar answered Oct 12 '22 13:10

Samuel


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.

like image 35
Justin R. Avatar answered Oct 12 '22 14:10

Justin R.


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

for each T item in MyEnumerable
{
    // Action<T> goes here
}
like image 5
Joel Coehoorn Avatar answered Oct 12 '22 15:10

Joel Coehoorn


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

like image 3
Joshua Belden Avatar answered Oct 12 '22 15:10

Joshua Belden