List<T>
有一个名为ForEach
的方法,它在每个元素上执行传递的操作。
var names = new List<String>{ "Bruce", "Alfred", "Tim", "Richard" };
names.ForEach(p => { Console.WriteLine(p); });
但如果 names
不是一个 List<T>
而是一个 IList<T>
呢?IList<T>
没有像 ForEach
这样的方法。
有没有其他替代方法?
List<T>
有一个名为ForEach
的方法,它在每个元素上执行传递的操作。
var names = new List<String>{ "Bruce", "Alfred", "Tim", "Richard" };
names.ForEach(p => { Console.WriteLine(p); });
但如果 names
不是一个 List<T>
而是一个 IList<T>
呢?IList<T>
没有像 ForEach
这样的方法。
有没有其他替代方法?
使用 foreach
循环:
foreach (var p in names) {
Console.WriteLine(p);
}
如果使用委托和扩展方法并没有真正提高可读性,则没有理由在各个地方都使用它们;使用 foreach
循环并不比使用 ForEach
方法更难以理解。
IList<T>
是一个数组 (T[]
),那么您可以像对 List<T>
使用 ForEach
方法一样,对其使用类似的 Array.ForEach 方法。 您可以为自定义的 IList<T>
或 IEnumerable<T>
创建扩展方法,或者其他您喜欢的方式。public static void ForEach<T>(this IList<T> list, Action<T> action)
{
foreach (T t in list)
action(t);
}
您只需要注意原始集合中的对象将被修改,但我想命名方式暗示了这一点。
------------------------------------------------------------------------------------------------------------------------------------
我更喜欢称之为:
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);
}
如果是这样,您可以在 IEnumerable
上创建扩展方法。请注意,终止调用 ForEach
执行了 Linq
查询。如果不想执行它,您也可以使用 yield
语句推迟它,并返回一个 IEnumerable<T>
:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T t in list)
{
action(t);
yield return t;
}
}
ForEach
的方法来最终执行调用。第二个原因是这样做并未为语言增加任何新的表示能力。”
Eric并不是说这样做是坏事-只是默认情况下不在Linq
中包含该结构的决定背后的哲学原因。如果您认为IEnumerable
上的函数不应对其内容进行操作,则不要这样做。个人而言,我并不介意它,因为我很清楚它的作用。我将其视为对集合类执行副作用的任何其他方法。我也可以进入函数并进行调试。这里还有一个来自Linq
本身的例子。people.Where(p => p.Tenure > 5)
.Select(p => p.Nationality)
.AsParallel()
.ForAll(n => AssignCitizenShip(n);
foreach
或需要在foreach
循环内执行超过一行的代码,则会变得难以阅读。但对于我发布的简单示例,我喜欢它。看起来干净简洁。
编辑: 还可以查看性能链接:为什么List<T>.ForEach比标准foreach更快?
void List<T>.ForEach(Action<T> action)
的实现。你可以在共享源代码计划网站下载源代码。
基本上,你会得到类似于以下的内容:
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<T>.ForEach方法
的开发人员可能会开始在您的IList引用上调用ToList
!我知道,因为它曾经在我的上一个项目中发生过。我在我们公共API的各个地方都使用集合接口,遵循Framework Design Guidelines。我花了一段时间才注意到很多开发人员不习惯这种做法,并且开始以惊人的速度调用ToList
。最后,我将这个扩展方法添加到一个所有人都在使用的通用程序集中,并确保从代码库中删除了所有不必要的ToList
调用。
将以下代码添加到静态类中,并将其称为扩展:
public static void ForEach<T>(this IList<T> list, Action<T> action) {
foreach(var item in list) {
action.Invoke(item);
}
}