用 IEnumerable 本来就是为遍历方便,可是现在只有两个选择:
1. foreach,示例代码如下:
IEnumerable<string> strs = new string[] { "a", "b" }; foreach (var str in strs) { Console.WriteLine(str); }
缺点:代码不简洁,不支持lamda
2. 先ToList,再ForEach,示例代码如下:
IEnumerable<string> strs = new string[] { "a", "b" }; strs.ToList().ForEach(str => Console.WriteLine(str));
缺点:ToList有性能代价。
如果 IEnumerable 直接提供 ForEach 操作,就可以这样:
IEnumerable<string> strs = new string[] { "a", "b" }; strs.ForEach(str => Console.WriteLine(str));
现在只能通过自己用扩展办法实现:
namespace System.Collections.Generic { public static class IEnumerableExtension { public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action) { foreach (var item in enumeration) { action(item); } } } }
我的问题是:
微软为什么不考虑到这一点,给IEnumerable增加 ForEach 操作?
为什么 List 有 ForEach 操作,而 IEnumerable 却没有,IEnumerable 更需要它,而且 List 实现了 IEnumerable ?
我的理解哈 ,这要分析IEnumerable对象的优势,和List等集合对象比较,它的优势在于将循环遍历的对象延迟到使用时创建。
也就是说,我们在循环一个IEnumerable枚举对象时,如果中途发现条件不满足了要结束遍历,那还未遍历的对象就不会再计算了,例子就不举了,亲可以了解下yield return的用法。
所以,基于此,假设IEnumerable提供ForEach方法,那势必会是一个Func而不是一个Action,因为要告诉调用者,何时可以结束遍历,而不是不顾一切的遍历完所有对象。如果是Func,那就会有歧义了;如果是Action ,则就更不应该是IEnumerable的成员了,因为丢失了对象延迟创建的特点,变得是抢了子类List的功了。
看看你的扩展方法,是不是必须要遍历完所有成员才会返回捏?
所以,我认为,微软的设计,确实是合情合理的。
题外:如果是Func的话,就类似jQuery的each方法,如果大量用到,写成一个扩展方法自己用还是比较好的
"如果中途发现条件不满足了要结束遍历,那还未遍历的对象就不会再计算了,例子就不举了"
求例子
可能是为了安全吧。
我分析过IEnumerable的方法GetEnumerator,它们生成的的IEnumertor对象基本上都是临时的。
不过,既然集合对象本身就是IEnumerable,似乎也不影响数据版本的安全问题。改天要电话的盖茨,诘问他为什么了^_^
不知道楼主是否有注意到ForEach是由List<T>提供的,并不是一个扩展函数。
换句话说,List<T>.ForEach 是一个特定的实现。
而 IEnumerable 和 IEnumerable<T> 是一个接口,因为兼容性的问题,在这个接口公开这么多年之后,在这个接口下增加一个方法是几乎不可能的事情,因为无法衡量代价有多大(天知道有多少人在代码中,依赖了这两个接口)。
而如果.net有提供类似的扩展函数的话,那一定会考虑加在 IEnumerable 和 IEnumerable<T> 上面的。
只是很不幸的,目前的版本木有这个扩展。
哈哈,还没去查看过FOREACH的代码,原来这样?就宛如IENUMERABLE不支持TOARRAY一样,如果是这样,那不支持FOREACH也就正常了。毕竟,IENUMERABLE要转换为ARRAY还是有难度的(性能上)。
ForEach扩展貌似有不少争议,毕竟和foreach循环不能完全等价,一个比较典型的例子是:
1 var numbers = new int[] { 1, 2, 3 }; 2 foreach (var num in numbers) 3 { 4 num *= 2; //这里编译报错 5 }
1 var numbers = new int[] { 1, 2, 3 }; 2 numbers.ForEach(num => num *= 2); //这里没语法错误,但一般这么写的人是想得到{2, 4, 6}的
官方扩展Enumerable类里没有ForEach确实不大方便,至于为什么也没见过官方的说明,说不定哪一天就把它给加上去了呢。记得微软曾经发布过一个扩展库Interactive Extensions(http://news.cnblogs.com/n/111128/),里面就有ForEach扩展的。
同一namespace下添加一个简单静态类,轻松解决
public static class TuoZhan
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
}