2012-12-19 30 views
34

可能重复:
LINQ equivalent of foreach for IEnumerable<T>有没有像ForEach for IList的方法?

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的方法。有其他选择吗?

+3

为什么你不能使用foreach循环? – BoltClock

+4

这被认为是一个坏主意,你究竟在获得什么?代码不会更短... - http://blogs.msdn.com/b/mazhou/archive/2011/09/21/why-no-foreach-method-on-ienumerable-interfaces.aspx – Maarten

+1

你可以添加ForEach作为IList 的扩展方法。 –

回答

35

使用foreach循环:

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

有没有理由在所有地方使用代理和扩展方法,如果这实际上不是即时通讯证明可读性;一个foreach循环与ForEach方法相比,并没有更明确地告诉读者正在做什么。

+2

我不同意最后一行。它使代码更短,更容易出错。为什么列表然后有一个Foreach? – nawfal

+7

@nawfal我非常赞同帖子的最后一行; '.ForEach'方法在很大程度上是过分的;它也不太直接。只使用普通的'foreach'优先于大部分 *所有*的情况。 –

+0

@nawfal:对一个ForEach方法调用的错误较少?必须插入具有兼容签名的正确委托这一事实将是发生错误的额外机会。至于关于'List '的问题,请查看[在此问题上选择的答案](http://stackoverflow.com/questions/800151/why-is-foreach-on-ilistt-and-not-on-ienumerablet ):“由于没有添加其他扩展方法,因此可以假定C#设计人员认为这是一个糟糕的设计,并且更喜欢'foreach'构造。”第二个答案就是这个问题。 –

15

如果您IList<T>是一个数组(T[]),那么你对他们Array.ForEach方法类似于ForEachList<T>。您可以为自定义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最终执行调用方法。

--------------------------------------------- -------------------------------------------------- ------------------------------------

为了解决有关偏好的相反观点,here is a better link来自Eric Lippert的比this。要引用他的话:

“第一个原因是,这样做违反了函数式编程的所有其他序列运营商基于 原则 显然,这种方法的调用的唯一目的是使侧 效果。表达式的目的是为了计算一个值,而不是对 造成副作用。一个语句的目的是引起一个方面 效应。这个东西的调用网站看起来很像一个 表达式(虽然,诚然,由于该方法是无效的返回, 该表达式只能在“语句表达式” 上下文中使用)。它不是很好与我作出唯一的 序列运算符,这只对其副作用有用。

第二个原因是,这样做增加了零新表象 电源语言”

埃里克并没有说这是一个坏的事情 - 只是哲学的决定不包括背后的原因在Linq构造默认情况下,如果你认为IEnumerable上的函数不应该对内容起作用,那么不要这样做,我个人不介意,因为我很清楚它的作用。其他方法会导致集合类的副作用,如果需要,我可以进入函数并调试它,下面是另一个从Linq本身。

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

正如我所说,这些没有什么不好。它只是个人的喜好。 我不会将它用于嵌套的foreach,或者它包含多于一行的代码以在foreach循环内执行,因为这是不可读的。但是我发布了一个简单的例子,我喜欢它。看起来干净简洁。

编辑:见BTW性能链接:Why is List<T>.ForEach faster than standard foreach?

+1

为什么要投票? – nawfal

+0

也许是因为你刚刚复制我的答案作为你的(这是比我大一分钟) – 2012-12-19 07:25:07

+5

@VirtualVoid这是一个虚假的说法;徘徊在所示的时间;你们列出了'2012-12-19 06:35:45Z',nawfal的名单'2012-12-19 06:35:81Z'。他实际上更老了。 –

2

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

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

你可以做一个扩展方法,并使用大部分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中包括索引优势,其他实现稍好。

虽然我同意O.R.Mapper的答案,有时候在有很多开发人员的大项目中,很难让每个人都确信foreach陈述更清楚。更糟糕的是,如果您的API基于接口(IList)而不是具体类型(List),那么习惯于List<T>.ForEach method的开发人员可能会开始在您的IList引用上调用ToList!我知道,因为它发生在我以前的项目中。我在Framework Design Guidelines之后的公共API中随处使用集合接口。我花了一段时间才注意到,许多不习惯此操作并致电ToList的开发人员开始以令人吃惊的速度刷新。最后,我将这种扩展方法添加到每个人都使用的常用程序集中,并确保从代码库中删除对ToList的所有不必要的调用。

+2

是的,因为'list .ForEach'不涉及转换(如在'foreach'中),速度更快。这里是一个相关的问题http://stackoverflow.com/questions/744085/why-is-listt-foreach-faster-than-standard-foreach?lq=1(不意味着因此它是有道理的,以避免'foreach') – nawfal

相关问题