I don't know for sure, but my guess is because there are at least two implementations with different semantics:
// immediate execution
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
return source;
}
// deferred execution
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
yield return item;
}
}
Which implementation is correct? The first one is correct if you want to force the iteration, the second is correct if you want to add lazy processing to a Linq pipeline. Interestingly, however, both violate the the principle of least astonishment: The first is dissimilar to most chainable Linq constructs because they use deferred execution where possible, and sophisticated consumers may be relying on this; the second does not meet many people's expectation that a construct named foreach should actually iterate over a collection.
If there are multiple conflicting solutions to a problem, where all solutions are equally valid and no solution is ideal, then sometimes the right choice is to implement nothing but provide the facilities to let the consumer easily implement the solution that is correct for them.
For the record, our core library function is as follows, because if you don't return a value then it is obvious that the method must execute immediately. This clarity comes at the expense of not being able to chain the method, but for us it's the right trade-off.
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
I guess that makes at least three implementations...
Posted
Jun 30 2008, 01:08 PM
by
Greg Beech