关于c#:有没有类似ForEach for IList的方法?


Is there any method like ForEach for IList?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
LINQ equivalent of foreach for IEnumerable

List有一个名为ForEach的方法,它对它的每个元素执行传递的操作。

1
2
3
var names = new List<String>{"Bruce","Alfred","Tim","Richard" };

names.ForEach(p =>  { Console.WriteLine(p); });

但是如果names不是List而是IList的话,IList就没有ForEach这样的方法了。还有别的选择吗?


使用ForEach循环:

1
2
3
foreach (var p in names) {
    Console.WriteLine(p);
}

如果委托和扩展方法不能提高可读性,那么就没有理由到处使用委托和扩展方法;ForEach循环比ForEach方法更能明确地告诉读者正在做什么。


如果你的IList是一个数组(T[]),那么你在它们上面有array.foreach方法,类似于List上的ForEach。您可以为您的自定义IListIEnumerable或您喜欢的任何内容创建扩展方法。

1
2
3
4
5
public static void ForEach<T>(this IList<T> list, Action<T> action)
{
    foreach (T t in list)
        action(t);
}

您只需注意这样一个事实:原始集合中的对象将被修改,但我猜命名确实意味着这一点。

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

我更喜欢打电话:

1
2
3
people.Where(p => p.Tenure > 5)
      .Select(p => p.Nationality)
      .ForEach(n => AssignCitizenShip(n);

1
2
3
4
foreach (var n in people.Where(p => p.Tenure > 5).Select(p => p.Nationality))
{
    AssignCitizenShip(n);
}

如果是这样,您可以在EDCOX1 OR 6中创建扩展方法。请注意,终止调用EDCOX1(2)执行EDOCX1×8查询。如果您不需要,也可以使用yield语句并返回IEnumerable来延迟它:

1
2
3
4
5
6
7
8
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
    foreach (T t in list)
    {
        action(t);
        yield return t;
    }
}

这解决了副作用问题,但我个人喜欢一个名为ForEach的方法来最终执行调用。

——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————---

为了解决对偏好的对立观点,埃里克·利珀特提供了一个比这更好的链接。引用他:

"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".

埃里克并没有说这是一件糟糕的事情——只是出于哲学上的原因,他决定不在默认情况下将构造包含在Linq中。如果您认为IEnumerable上的函数不应该作用于内容,那么就不要这样做。我个人并不介意,因为我很清楚它的作用。我将它视为对集合类产生副作用的任何其他方法。如果需要的话,我可以进入函数并调试它。这是另一个来自Linq本身的。

1
2
3
4
people.Where(p => p.Tenure > 5)
      .Select(p => p.Nationality)
      .AsParallel()
      .ForAll(n => AssignCitizenShip(n);

正如我想说的,这些没有什么不好的。这只是个人喜好。我不会在嵌套的ForEach中使用它,或者如果它涉及多行代码在ForEach循环中执行,因为这显然是不可读的。但举个简单的例子,我喜欢它。看起来简洁明了。

编辑:请参见性能链接btw:Why is list.foreach speed than standard foreach?


您可以创建一个扩展方法并使用void List.ForEach(Action action)的大部分实现。您可以在共享源代码计划站点下载源代码。

基本上你会结束这样的事情:

1
2
3
4
5
6
7
8
9
10
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]);
    }
}

它比使用ForEach语句的其他实现稍好,因为它利用了这样一个事实,即ilist包含索引器。

虽然我赞同O.R.Mapper的回答,但有时在许多开发人员参与的大型项目中,很难让每个人都相信ForEach的声明更清晰。更糟糕的是,如果您的API是基于接口(ilist)而不是具体类型(list),那么用于List.ForEach method的开发人员可能会开始在您的ilist引用上调用ToList!我知道,因为它发生在我以前的项目中。我按照框架设计指南在公共API中的任何地方使用了集合接口。我花了一段时间才注意到,许多不习惯这种做法的开发人员开始以惊人的速度逮捕ToList。最后,我将这个扩展方法添加到每个人都在使用的公共程序集中,并确保从代码库中删除对ToList的所有不必要的调用。


将此代码添加到静态类并调用它的扩展名:

1
2
3
4
5
public static void ForEach<T>(this IList<T> list, Action<T> action) {
    foreach(var item in list) {
        action.Invoke(item);
    }
}