首页 新闻 赞助 找找看

IEnumerable 为什么不提供支持 ForEach 操作

1
悬赏园豆:20 [已解决问题] 解决于 2012-06-16 16:23

用 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 ?

dudu的主页 dudu | 高人七级 | 园豆:31075
提问于:2012-05-30 15:23
< >
分享
最佳答案
1
我的理解哈 ,这要分析IEnumerable对象的优势,和List等集合对象比较,它的优势在于将循环遍历的对象延迟到使用时创建。
也就是说,我们在循环一个IEnumerable枚举对象时,如果中途发现条件不满足了要结束遍历,那还未遍历的对象就不会再计算了,例子就不举了,亲可以了解下yield return的用法。
所以,基于此,假设IEnumerable提供ForEach方法,那势必会是一个Func而不是一个Action,因为要告诉调用者,何时可以结束遍历,而不是不顾一切的遍历完所有对象。如果是Func,那就会有歧义了;如果是Action ,则就更不应该是IEnumerable的成员了,因为丢失了对象延迟创建的特点,变得是抢了子类List的功了。

看看你的扩展方法,是不是必须要遍历完所有成员才会返回捏?

所以,我认为,微软的设计,确实是合情合理的。

题外:如果是Func的话,就类似jQuery的each方法,如果大量用到,写成一个扩展方法自己用还是比较好的
收获园豆:20
abeno | 菜鸟二级 |园豆:222 | 2012-06-16 14:37

"如果中途发现条件不满足了要结束遍历,那还未遍历的对象就不会再计算了,例子就不举了"

 

求例子

magicdawn | 园豆:197 (初学一级) | 2014-01-02 18:39
其他回答(5)
0

可能是为了安全吧。

我分析过IEnumerable的方法GetEnumerator,它们生成的的IEnumertor对象基本上都是临时的。

不过,既然集合对象本身就是IEnumerable,似乎也不影响数据版本的安全问题。改天要电话的盖茨,诘问他为什么了^_^

无之无 | 园豆:5095 (大侠五级) | 2012-05-30 15:34
-2

不知道楼主是否有注意到ForEach是由List<T>提供的,并不是一个扩展函数。

换句话说,List<T>.ForEach 是一个特定的实现。

而 IEnumerable 和 IEnumerable<T> 是一个接口,因为兼容性的问题,在这个接口公开这么多年之后,在这个接口下增加一个方法是几乎不可能的事情,因为无法衡量代价有多大(天知道有多少人在代码中,依赖了这两个接口)。

而如果.net有提供类似的扩展函数的话,那一定会考虑加在 IEnumerable 和 IEnumerable<T> 上面的。

只是很不幸的,目前的版本木有这个扩展。

路人已 | 园豆:228 (菜鸟二级) | 2012-05-30 17:08
1
dotNetDR_ | 园豆:2078 (老鸟四级) | 2012-05-30 18:53

哈哈,还没去查看过FOREACH的代码,原来这样?就宛如IENUMERABLE不支持TOARRAY一样,如果是这样,那不支持FOREACH也就正常了。毕竟,IENUMERABLE要转换为ARRAY还是有难度的(性能上)。

支持(0) 反对(0) 无之无 | 园豆:5095 (大侠五级) | 2012-05-30 20:02
1

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扩展的。

天方 | 园豆:5407 (大侠五级) | 2012-05-30 23:55
0

同一namespace下添加一个简单静态类,轻松解决
public static class TuoZhan
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
{
action(item);
}
}
}

yyxu | 园豆:202 (菜鸟二级) | 2020-02-03 11:29
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册