Why .ForEach () on IList <T> and not on IEnumerable <T>?
Possible duplicate:
Why is there no ForEach extension method in the IEnumerable interface?
I noticed that when writing LINQ-y .ForEach() code is a good idiom. For example, here is a piece of code that takes the following input and produces this output:
{ "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(); } Notice the inserted .ToList() before .ForEach() from the second to the last line.
Why is .ForEach() not available as an extension method in IEnumerable<T> ? With such an example, this seems strange.
Because ForEach(Action) existed before IEnumerable<T> .
Since it was not added with other extension methods, it can be assumed that C # designers thought this was a bad design and preferred the foreach construct.
Edit:
If you want to create your own extension method, it will not override the value for List<T> , but it will work for any other class that 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); } } According to Eric Lippert, this is mainly for philosophical reasons . You should read the whole post, but here is the point, as far as I know:
I philosophically object to providing such a method for two reasons.
The first reason is because functional programming principles are so disturbed that all other sequences of operators are based on. Clearly, the only purpose of calling this method is to cause side effects.
The purpose of the expression is to compute the value, and not cause a side effect. The purpose of the application is to cause a side effect. A site calling this thing would be horrible as an expression (although admittedly, since the void-return method, the expression could only be used in the statement expression. ")
I do not really like to do a single-sequence operator; this is only useful for its side effects.
The second reason is that it adds zero new representative power to the language.
Because ForEach() in IEnumerable is normal for each loop as follows:
for each T item in MyEnumerable { // Action<T> goes here } I am just guessing here, but setting foreach to IEnumerable will cause operations on it to have side effects. None of the “available” extension methods cause side effects, imposing an imperative method like foreach, there will be a muddy api, I think. In addition, foreach initializes a lazy collection.
Personally, I was tempted to simply add my own, just to keep the side effects of free functions separate from those who have side effects.
ForEach is not listed. You used a specific list in your example.
I honestly don’t know for sure why .ForEach (Action) is not included in IEnumerable, but, correctly, incorrectly, or doesn’t care if it is so ...
However, I wanted to highlight the performance issue mentioned in other comments. There is a performance hit based on how you iterate over the collection. It is relatively insignificant, but, nevertheless, it certainly exists. Here's an incredibly fast and messy piece of code to show relationships ... it only takes minutes or so.
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 it too much. Performance is the currency of application design, but if your application does not encounter an actual performance hit that causes usability problems, focus on coding for maintenance and reuse, as time is the currency of real business projects ...
ForEach is implemented in a specific List<T> class List<T>
It is called "Select" on I am enlightened, thanks.IEnumerable<T>
Just a guess, but List can iterate over elements 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 increased productivity. With IEnumerable, you have no way to use normal for a loop.
LINQ follows the pull model, and all of its methods (extensions) should return an IEnumerable<T> , with the exception of ToList() . ToList() exists to complete the pull chain.
ForEach() - from the world of the push model.
You can still write your own extension method to do this, as Samuel pointed out.