如果您的 IList<T> 是一个数组 (T[]),那么您对它们有 Array.ForEach 方法,类似于 List<T> 上的 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);
比
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 Lippert 的 here is a better link 比 this 。引用他的话:
"第一个原因是这样做违反了函数式编程
所有其他序列运算符都基于的原则。
显然,调用此方法的唯一目的是引起侧
效果。表达式的目的是计算一个值,而不是
造成副作用。声明的目的是引起一方
影响。这个东西的调用站点看起来很像一个
表达式(虽然,诚然,由于该方法是返回无效的,
该表达式只能在“语句表达式”中使用
上下文。)我不喜欢做一个唯一的
仅对其副作用有用的序列运算符。
第二个原因是这样做会增加零新的代表性
语言的力量”。
Eric 并不是说这样做是一件坏事 - 只是决定在默认情况下不在 Linq 中包含该构造背后的哲学原因。如果您认为 IEnumerable 上的函数不应该作用于内容,那么不要这样做。就我个人而言,我不介意它,因为我很清楚它的作用。我将其视为对集合类造成副作用的任何其他方法。如果需要,我也可以进入该函数并对其进行调试。这是Linq 本身的另一个。
people.Where(p => p.Tenure > 5)
.Select(p => p.Nationality)
.AsParallel()
.ForAll(n => AssignCitizenShip(n);
正如我所说,这些并没有什么不好。它只是个人喜好。 我不会将它用于嵌套的 foreachs,或者如果它涉及在 foreach 循环内执行的多行代码,因为那是完全不可读的。但对于我发布的简单示例,我喜欢它。看起来干净简洁。
编辑:顺便查看性能链接:Why is List<T>.ForEach faster than standard foreach?