有没有像ForEach for IList的方法?
可能重复:
IEnumerable <T>的foreach相当于LINQ
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[]
),那么你的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比这更好的一个链接。 引用他的话:
“第一个原因是这样做违反了所有其他序列操作符所基于的函数式编程原则,显然调用这个方法的唯一目的是引起副作用,表达式的目的是计算一个值,不会导致副作用,声明的目的是引起副作用,这个东西的调用网站看起来很像一个表达式(虽然,虽然,由于该方法是无效的 - 返回,表达式只能在“语句表达式”上下文中使用)。对于仅对唯一有用的副作用进行序列操作的人来说,它并不适合我。
第二个原因是这样做为语言增添了零代表性的力量“。
埃里克并不是说这是一件坏事 - 只是决定不在Linq
包含构造的哲学原因。 如果您认为IEnumerable
上的函数不应该对内容执行操作,那么请不要这样做。 我个人不介意,因为我很清楚它的功能。 我把它当作对集合类产生副作用的其他方法。 如果需要,我可以进入该功能并进行调试。 这里是Linq
本身的另一个。
people.Where(p => p.Tenure > 5)
.Select(p => p.Nationality)
.AsParallel()
.ForAll(n => AssignCitizenShip(n);
正如我所说,这些没有什么不好。 它只是个人的喜好。 我不会将它用于嵌套的foreach
或者如果它涉及多于一行的代码在foreach
循环内执行,因为这是不可读的。 但对于我发布的简单例子,我喜欢它。 看起来干净简洁。
编辑:看到一个性能链接顺便说一句:为什么列表<T> .ForEach比标准的foreach更快?
你可以做一个扩展方法,并使用void List<T>.ForEach(Action<T> action)
大部分实现。 您可以在Shared Source Initiative网站下载源代码。
基本上你会结束这样的事情:
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包含索引器这一事实。
虽然我与OR Mapper的答案一致,有时在与许多开发人员合作的大型项目中,很难让每个人都确信foreach
语句更清晰。 更糟糕的是,如果您的API基于接口(IList)而不是具体类型(List),那么习惯于List<T>.ForEach method
开发人员可能会开始在您的IList引用上调用ToList
! 我知道,因为它发生在我以前的项目中。 我遵循框架设计指南在我们的公共API中随处使用集合接口。 我花了一段时间才能发现,许多开发商那里不习惯这一点,并调用ToList
开始以惊人的速度apprearing。 最后,我将这种扩展方法添加到每个人都使用的常用程序集中,并确保所有对ToList
不必要调用都从代码库中删除。
上一篇: Is there any method like ForEach for IList?
下一篇: call a function for each value in a generic c# collection