[ACCEPTED]-Why is .ForEach() on IList<T> and not on IEnumerable<T>?-ienumerable
Because ForEach(Action)
existed before IEnumerable<T>
existed.
Since it 7 was not added with the other extension methods, one 6 can assume that the C# designers felt it 5 was a bad design and prefer the foreach
construct.
Edit:
If 4 you want you can create your own extension 3 method, it won't override the one for a 2 List<T>
but it will work for any other class which 1 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 mostly for philosophical reasons. You 20 should read the whole post, but here's the 19 gist as far as I'm concerned:
I am philosophically 18 opposed to providing such a method, for 17 two reasons.
The first reason is that doing 16 so violates the functional programming principles 15 that all the other sequence operators are 14 based upon. Clearly the sole purpose of 13 a call to this method is to cause side effects.
The 12 purpose of an expression is to compute a 11 value, not to cause a side effect. The purpose 10 of a statement is to cause a side effect. The 9 call site of this thing would look an awful 8 lot like an expression (though, admittedly, since 7 the method is void-returning, the expression 6 could only be used in a “statement expression” context.)
It 5 does not sit well with me to make the one 4 and only sequence operator that is only 3 useful for its side effects.
The second reason 2 is that doing so adds zero new representational 1 power to the language.
Because ForEach()
on an IEnumerable is just a normal 1 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 1 were using the concrete List in your example.
I am just guessing here , but putting foreach 10 on IEnumerable would make operations on 9 it to have side effects . None of the "available" extension 8 methods cause side effects , putting an 7 imperative method like foreach on there 6 would muddy the api I guess . Also, foreach 5 would initialize the lazy collection .
Personally 4 I've been fending off the temptation to 3 just add my own , just to keep side effect 2 free functions separate from ones with side 1 effects.
ForEach is implemented in the concrete class 1 List<T>
Just a guess, but List can iterate over 4 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 3 can lead to better performance. With IEnumerable, you 2 don't have the option to use an ordinary 1 for-loop.
LINQ follows the pull-model and all its 5 (extension) methods should return IEnumerable<T>
, except 4 for ToList()
. The ToList()
is there to end the pull-chain.
ForEach()
is 3 from the push-model world.
You can still 2 write your own extension method to do this, as 1 pointed out by Samuel.
I honestly don't know for sure why the .ForEach(Action) isn't 17 included on IEnumerable but, right, wrong 16 or indifferent, that's the way it is...
I 15 DID however want to highlight the performance 14 issue mentioned in other comments. There 13 is a performance hit based on how you loop 12 over a collection. It is relatively minor 11 but nevertheless, it certainly exists. Here 10 is an incredibly fast and sloppy code snippet 9 to show the relations... only takes a minute 8 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 7 this too much though. Performance is the 6 currency of application design but unless 5 your application is experiencing an actual 4 performance hit that is causing usability 3 problems, focus on coding for maintainability 2 and reuse since time is the currency of 1 real life business projects...
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.