ChatGPT解决这个技术问题 Extra ChatGPT

Why is there no ForEach extension method on IEnumerable?

Inspired by another question asking about the missing Zip function:

Why is there no ForEach extension method on the IEnumerable interface? Or anywhere? The only class that gets a ForEach method is List<>. Is there a reason why it's missing, maybe performance?

Its probably as hinted by an earlier post, in that foreach is supported as a language keyword in C# and VB.NET (and many others) Most people (myself included) simply write one themselves as needed and appropriate.
Related question here with link to 'official answer' stackoverflow.com/questions/858978/…
I think one very important point is, that a foreach loop is easier to spot. If you use .ForEach(...) it easy to miss this one, when you look through the code. This becomes important, when you have performance issues. Of course .ToList() and .ToArray() have the same issue but they are used a little different. Another reason could be that it's more common in a .ForEach to modify the source list (f.e. removing/adding elements) so it would not be a "pure" query anymore.
When debugging parallelised code, I often try swapping Parallel.ForEach for Enumerable.ForEach only to rediscover the latter doesn't exist. C# missed a trick to make things easy here.

S
Sergey

There is already a foreach statement included in the language that does the job most of the time.

I'd hate to see the following:

list.ForEach( item =>
{
    item.DoSomething();
} );

Instead of:

foreach(Item item in list)
{
     item.DoSomething();
}

The latter is clearer and easier to read in most situations, although maybe a bit longer to type.

However, I must admit I changed my stance on that issue; a ForEach() extension method would indeed be useful in some situations.

Here are the major differences between the statement and the method:

Type checking: foreach is done at runtime, ForEach() is at compile time (Big Plus!)

The syntax to call a delegate is indeed much simpler: objects.ForEach(DoSomething);

ForEach() could be chained: although evilness/usefulness of such a feature is open to discussion.

Those are all great points made by many people here and I can see why people are missing the function. I wouldn't mind Microsoft adding a standard ForEach method in the next framework iteration.


The discussion here gives the answer: forums.microsoft.com/MSDN/… Basically the decision was made to keep the extension methods functionally "pure". A ForEach would encourage side-effects when using the extension methods, which was not the intent.
'foreach' may seem clearer if you have a C background, but internal iteration more clearly states your intent. That means you could do things like 'sequence.AsParallel().ForEach(...)'.
I'm not sure your point about type checking is correct. foreach is type checked at compile time if the enumerable is parameterised. It only lacks compile time type checking for non-generic collections, as would a hypothetical ForEach extension method.
Extension method would be really useful in chain LINQ with dot notation, like: col.Where(...).OrderBy(...).ForEach(...). Much simpler syntax, no screen pollution with either redundant local variables or long brackets in foreach().
"I'd hate to see the following" -- The question wasn't about your personal preferences, and you made the code more hateful by adding extraneous linefeeds and an extraneous pair of braces. Not so hateful is list.ForEach(item => item.DoSomething()). And who says it's a list? The obvious use case is at the end of a chain; with the foreach statement, you would have to put the whole chain after in, and the operation to performed inside the block, which is far less natural or consistent.
a
aku

ForEach method was added before LINQ. If you add ForEach extension, it will never be called for List instances because of extension methods constraints. I think the reason it was not added is to not interference with existing one.

However, if you really miss this little nice function, you can roll out your own version

public static void ForEach<T>(
    this IEnumerable<T> source,
    Action<T> action)
{
    foreach (T element in source) 
        action(element);
}

The extension methods allow for this. If there is already an instance implementation of a given method name then that method is used instead of the extension method. So you can implement an extension method ForEach and not have it collide with the List<>.ForEach method.
Cameron, believe me I know how extension methods work :) List inherits IEnumerable so it will be non-obvious thing.
From the Extension Methods Programming Guide (msdn.microsoft.com/en-us/library/bb383977.aspx): An extension method with the same name and signature as an interface or class method will never be called. Seems pretty obvious to me.
Am I talking something different? I think it's no good when many classes have ForEach method but some of them may work differently.
One interesting thing to note about List<>.ForEach and Array.ForEach is that they are not actually using the foreach construct internally. They both use a plain for loop. Maybe it's a performance thing (diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx). But given that, Array and List both implement ForEach methods, it's surprising that they didn't at least implement an extension method for IList<>, if not for IEnumerable<> too.
J
Jay Bazuzi

You could write this extension method:

// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
    foreach (var e in source)
    {
        action(e);
        yield return e;
    }
}

Pros

Allows chaining:

MySequence
    .Apply(...)
    .Apply(...)
    .Apply(...);

Cons

It won't actually do anything until you do something to force iteration. For that reason, it shouldn't be called .ForEach(). You could write .ToList() at the end, or you could write this extension method, too:

// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
    foreach (var e in source)
    {
        // do nothing
        ;
    }

    return source;
}

This may be too significant a departure from the shipping C# libraries; readers who are not familiar with your extension methods won't know what to make of your code.


Your first function could be used w/out the 'realize' method if written like: {foreach (var e in source) {action(e);} return source;}
Couldn't you just use Select instead of your Apply method? It seems to me that applying an action to each element and yielding it is exactly what Select does. E.g. numbers.Select(n => n*2);
I think Apply is more readable than using Select for this purpose. When reading a Select statement, I read it as "get something from inside" where as Apply is "do some work to".
@rasmusvhansen Actually, Select() says apply a function to each element and return the value of the function where Apply() says apply an Action to each element and return the original element.
This is equivalent to Select(e => { action(e); return e; })
s
sashoalm

The discussion here gives the answer:

Actually, the specific discussion I witnessed did in fact hinge over functional purity. In an expression, there are frequently assumptions made about not having side-effects. Having ForEach is specifically inviting side-effects rather than just putting up with them. -- Keith Farmer (Partner)

Basically the decision was made to keep the extension methods functionally "pure". A ForEach would encourage side-effects when using the Enumerable extension methods, which was not the intent.


See also blogs.msdn.com/b/ericlippert/archive/2009/05/18/… . Ddoing 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
That reasoning is completely bogus. The use case is that side effects are needed ... without ForEach, you have to write a foreach loop. The existence of ForEach does not encourage side effects and its absence does not reduce them.
Given how simple it is to write the extension method, there's literally no reason that it's not language standard.
Archive for @MichaelFreidgeim's now dead link: web.archive.org/web/20151205151706/http://blogs.msdn.com/b/…
C
Chris Zwiryk

While I agree that it's better to use the built-in foreach construct in most cases, I find the use of this variation on the ForEach<> extension to be a little nicer than having to manage the index in a regular foreach myself:

public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
    if (action == null) throw new ArgumentNullException("action");

    var index = 0;

    foreach (var elem in list)
        action(index++, elem);

    return index;
}
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

Would give you:

Person #0 is Moe
Person #1 is Curly
Person #2 is Larry

Great extension, but could you add some documentation? What is the intended use of the returned value? Why is index var rather than specifically an int? Sample usage?
Mark: The return value is the number of elements in the list. Index is specifically typed as an int, thanks to implicit typing.
@Chris, based on your code above, the return value is the zero-based index of the last value in the list, not the number of elements in the list.
@Chris, no it isn't: index is incremented after the value has been taken (postfix increment), so after the first element has been processed, index will be 1 and so on. So the return value really is the element count.
@MartinStettner the comment from Eric Smith on 5/16 was from an earlier version. He corrected the code on 5/18 to return the correct value.
J
Jay Bazuzi

One workaround is to write .ToList().ForEach(x => ...).

pros

Easy to understand - reader only needs to know what ships with C#, not any additional extension methods.

Syntactic noise is very mild (only adds a little extranious code).

Doesn't usually cost extra memory, since a native .ForEach() would have to realize the whole collection, anyway.

cons

Order of operations isn't ideal. I'd rather realize one element, then act on it, then repeat. This code realizes all elements first, then acts on them each in sequence.

If realizing the list throws an exception, you never get to act on a single element.

If the enumeration is infinite (like the natural numbers), you're out of luck.


a) This is not even remotely an answer to the question. b) This response would be clearer if it mentioned up front that, while there is no Enumerable.ForEach<T> method, there is a List<T>.ForEach method. c) "Doesn't usually cost extra memory, since a native .ForEach() would have to realize the whole collection, anyway." -- complete and utter nonsense. Here is the implementation of Enumerable.ForEach<T> that C# would provide if it did: public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
A
Alexandr Nikitin

I've always wondered that myself, that is why that I always carry this with me:

public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
    if (action == null)
    {
        throw new ArgumentNullException("action");
    }
    foreach (var item in col)
    {
        action(item);
    }
}

Nice little extension method.


col could be null... you could check that as well.
Yeah I do check in my library, I just missed it when doing it quickly there.
I find it interesting that everyone checks the action parameter for null, but never the source/col parameter.
I find it interesting that everyone checks parameters for null, when not checking results in an exception as well...
Not at all. A Null Ref exception wouldn't tell you the name of the parameter that was at fault. And you might also check in the loop so you could throw a specific Null Ref saying col[index#] was null for the same reason
S
Scott Dorman

So there has been a lot of comments about the fact that a ForEach extension method isn't appropriate because it doesn't return a value like the LINQ extension methods. While this is a factual statement, it isn't entirely true.

The LINQ extension methods do all return a value so they can be chained together:

collection.Where(i => i.Name = "hello").Select(i => i.FullName);

However, just because LINQ is implemented using extension methods does not mean that extension methods must be used in the same way and return a value. Writing an extension method to expose common functionality that does not return a value is a perfectly valid use.

The specific arguement about ForEach is that, based on the constraints on extension methods (namely that an extension method will never override an inherited method with the same signature), there may be a situation where the custom extension method is available on all classes that impelement IEnumerable<T> except List<T>. This can cause confusion when the methods start to behave differently depending on whether or not the extension method or the inherit method is being called.


J
Jim Balter

You could use the (chainable, but lazily evaluated) Select, first doing your operation, and then returning identity (or something else if you prefer)

IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });

You will need to make sure it is still evaluated, either with Count() (the cheapest operation to enumerate afaik) or another operation you needed anyway.

I would love to see it brought in to the standard library though:

static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
  return src.Select(i => { action(i); return i; } );
}

The above code then becomes people.WithLazySideEffect(p => Console.WriteLine(p)) which is effectively equivalent to foreach, but lazy and chainable.


Fantastic, it never clicked that a returned select would work like this. A nice use of the method syntax, as I don't think you could do this with the expression syntax (hence I've not thought of it like this before).
@AlexKeySmith You could do it with expression syntax if C# had a sequence operator, like its forebear. But the whole point of ForEach is that it takes an action with void type, and you can't use void types in expressions in C#.
imho, now the Select doesn't do anymore what it's supposed to do. it's definitely a solution for what the OP asks - but on topic readability: nobody would expect that the select does execute a function.
@MatthiasBurger If Select doesn't do what it's supposed to do that's a problem with the implementation of Select, not with the code that calls Select, which has no influence over what Select does.
D
Dave Clausen

Note that the MoreLINQ NuGet provides the ForEach extension method you're looking for (as well as a Pipe method which executes the delegate and yields its result). See:

https://www.nuget.org/packages/morelinq

https://code.google.com/p/morelinq/wiki/OperatorsOverview


s
spoulson

@Coincoin

The real power of the foreach extension method involves reusability of the Action<> without adding unnecessary methods to your code. Say that you have 10 lists and you want to perform the same logic on them, and a corresponding function doesn't fit into your class and is not reused. Instead of having ten for loops, or a generic function that is obviously a helper that doesn't belong, you can keep all of your logic in one place (the Action<>. So, dozens of lines get replaced with

Action<blah,blah> f = { foo };

List1.ForEach(p => f(p))
List2.ForEach(p => f(p))

etc...

The logic is in one place and you haven't polluted your class.


foreach (var p in List1.Concat(List2).Concat(List3)) { ... do stuff... }
If it's as simple as f(p), then leave out the { } for shorthand: for (var p in List1.Concat(List2).Concat(List2)) f(p);.
l
leppie

Most of the LINQ extension methods return results. ForEach does not fit into this pattern as it returns nothing.


ForEach uses Action, which is another form of delegate
Except leppie's right, all the Enumerable extension methods return a value, so ForEach doesn't fit the pattern. Delegates doesn't come into this.
Just that an extension method doesn't have to return a result, it serves the purpose of adding a way to call a frequently used operation
Indeed, Slace. So what if it doesn't return a value?
@Martijn i.e. public IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
v
vzwick

If you have F# (which will be in the next version of .NET), you can use

Seq.iter doSomething myIEnumerable


So Microsoft chose not to provide a ForEach method for an IEnumerable in C# and VB, because it would not be purely functional; yet they DID provide it (name iter) in their more functional language, F#. Their logic alludes me.
M
McKay

Partially it's because the language designers disagree with it from a philosophical perspective.

Not having (and testing...) a feature is less work than having a feature.

It's not really shorter (there's some passing function cases where it is, but that wouldn't be the primary use).

It's purpose is to have side effects, which isn't what linq is about.

Why have another way to do the same thing as a feature we've already got? (foreach keyword)

https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/


P
Paco

You can use select when you want to return something. If you don't, you can use ToList first, because you probably don't want to modify anything in the collection.


a) This is not an answer to the question. b) ToList requires extra time and memory.
K
Kirill Osenkov

I wrote a blog post about it: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

You can vote here if you'd like to see this method in .NET 4.0: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093


was this ever implemented? I imagine not, but is there any other URL that replaces that ticket? MS connect has been discontinued
This wasn't implemented. Consider filing a new issue on github.com/dotnet/runtime/issues
C
Community

In 3.5, all the extension methods added to IEnumerable are there for LINQ support (notice that they are defined in the System.Linq.Enumerable class). In this post, I explain why foreach doesn't belong in LINQ: Existing LINQ extension method similar to Parallel.For?


d
davidsleeps

Is it me or is the List.Foreach pretty much been made obsolete by Linq. Originally there was

foreach(X x in Y) 

where Y simply had to be IEnumerable (Pre 2.0), and implement a GetEnumerator(). If you look at the MSIL generated you can see that it is exactly the same as

IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
    int i = enumerator.Current;

    Console.WriteLine(i);
}

(See http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx for the MSIL)

Then in DotNet2.0 Generics came along and the List. Foreach has always felt to me to be an implementation of the Vistor pattern, (see Design Patterns by Gamma, Helm, Johnson, Vlissides).

Now of course in 3.5 we can instead use a Lambda to the same effect, for an example try http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh-my/


I believe the generated code for "foreach" should have a try-finally block. Because IEnumerator of T inherits from interface IDisposable. So, in the generated finally block, the IEnumerator of T instance should Disposed.
C
Community

I would like to expand on Aku's answer.

If you want to call a method for the sole purpose of it's side-effect without iterating the whole enumerable first you can use this:

private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
    foreach (var x in xs) {
        f(x); yield return x;
    }
}

This is the same as Select(x => { f(x); return x;})
L
Liran Barniv

My version an extension method which would allow you to use ForEach on IEnumerable of T

public static class EnumerableExtension
{
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        source.All(x =>
        {
            action.Invoke(x);
            return true;
        });
    }
}

S
Squirrel

No one has yet pointed out that ForEach results in compile time type checking where the foreach keyword is runtime checked.

Having done some refactoring where both methods were used in the code, I favor .ForEach, as I had to hunt down test failures / runtime failures to find the foreach problems.


Is this really the case? I fail to see how foreach has any less compile time checking. Sure, if your collection is a non-generic IEnumerable, the loop variable will be an object, but the same would be true for a hypothetical ForEach extension method.
This is mentioned in the accepted answer. However, it is simply wrong (and Richard Poole above is correct).