Is there any method like ForEach for IList?

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?


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?


You could make an extension method and use most of the implementation of void List<T>.ForEach(Action<T> action) . You can download the source code at the Shared Source Initiative site.

Basically you will end to something like this:

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

    for (int i = 0; i < list.Count; i++)
    {
        action(list[i]);
    }
}

It is slightly better than the other implementations that use the foreach statement since it takes advantage of the fact that IList includes an indexer.

Although I aggree with the answer of OR Mapper, sometimes in big projects with many developers it is hard to convicne everybody that a foreach statement is clearer. Even worse, if your API is based on interfaces (IList) instead of concrete types (List) then developers that are used to the List<T>.ForEach method might start calling ToList on your IList references! I know because it happened in my previous project. I was using the collection interfaces everywhere in our public APIs following the Framework Design Guidelines. It took me a while to notice that many developers where not used to this and call to ToList started apprearing with an alarming rate. Finally I added this extension method to a common assembly that everybody was using and made sure that all unecessary call to ToList were removed from the codebase.

链接地址: http://www.djcxy.com/p/52998.html

上一篇: 在列表<>上选择和ForEach

下一篇: 有没有像ForEach for IList的方法?