Possible Duplicate:
LINQ equivalent of foreach for IEnumerable<T>
List<T>
has a method called ForEach
which executes the passed action on each element of it.
var names = new List<String>{ "Bruce", "Alfred", "Tim", "Richard" }; names.ForEach(p => { Console.WriteLine(p); });
But what if names
is not a List<T>
but an IList<T>
? IList<T>
doesn't have a method like ForEach
.
Is there some alternative?
In C#, it is not strictly necessary for a collection class to implement IEnumerable and IEnumerator in order to be compatible with foreach . As long as the class has the required GetEnumerator , MoveNext , Reset , and Current members, it will work with foreach .
Convert a foreach loop to LINQ refactoringPlace your cursor in the foreach keyword. Press Ctrl+. to trigger the Quick Actions and Refactorings menu. Select Convert to LINQ or Convert to Linq (call form).
Using the CodeThe ForEach method of the List<T> (not IList<T> ) executes an operation for every object which is stored in the list. Normally it contains code to either read or modify every object which is in the list or to do something with list itself for every object.
Use a foreach
loop:
foreach (var p in names) { Console.WriteLine(p); }
There is no reason to use delegates and extension methods all over the place if that doesn't actually improve readability; a foreach
loop is not any less explicitly telling readers what's being done than a ForEach
method.
If your IList<T>
is an array (T[]
), then you have Array.ForEach method on them similar to ForEach
on List<T>
. You can create an extension method for your custom IList<T>
or IEnumerable<T>
or whatever you prefer.
public static void ForEach<T>(this IList<T> list, Action<T> action) { foreach (T t in list) action(t); }
You just have to be wary of the fact that the objects in the original collection will be modified, but I guess the naming does imply that.
------------------------------------------------------------------------------------------------------------------------------------
I prefer to call:
people.Where(p => p.Tenure > 5) .Select(p => p.Nationality) .ForEach(n => AssignCitizenShip(n);
than
foreach (var n in people.Where(p => p.Tenure > 5).Select(p => p.Nationality)) { AssignCitizenShip(n); }
If so you can create the extension method on IEnumerable
. Mind you the terminating call ForEach
executes the Linq
query. If you do not want it, you can defer it too by using yield
statement and returning an IEnumerable<T>
back:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T t in list) { action(t); yield return t; } }
That solves the side-effect issue, but I personally like a method named ForEach
to finally execute the call.
-----------------------------------------------------------------------------------------------------------------------------------
To address the opposing views on preferences, here is a better link from Eric Lippert than this. To quote him:
"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".
Eric's not saying it's a bad thing to do - just the philosophical reasons behind the decision to not include the construct in Linq
by default. If you believe a function on an IEnumerable
shouldn't act on the contents, then don't do it. Personally I dont mind it since I'm well aware what it does. I treat it as any other method that causes side-effect on a collection class. I can enter into the function and debug it too if I want. Here is another one from Linq
itself.
people.Where(p => p.Tenure > 5) .Select(p => p.Nationality) .AsParallel() .ForAll(n => AssignCitizenShip(n);
As I would say, there is nothing bad about these. Its just personal preference. I wouldn't use this for nested foreach
s or if it involves more than one line of code to execute inside the foreach
loop since thats plain unreadable. But for simple example I posted, I like it. Looks clean and concise.
Edit: See a performance link btw: Why is List<T>.ForEach faster than standard foreach?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With