在IEnumerable上使用扩展方法的foreach循环

5

快速问题,看一下这段代码:

List<int> result = new List<int>();

var list = new List<int> { 1, 2, 3, 4 };

list.Select(value =>
    {
        result.Add(value);//Does not work??
        return value;
    });

并且:

result.Count == 0 //true

为什么result.Add(value)没有被执行?

然而,这个没有被执行。还有一个问题,有没有办法用扩展方法在IEnumerable上进行foreach循环?

除了这种方式:IEnumerable.ToList().Foreach(p=>...)


1
@DJKRAZE 它已经是一个委托。 - Felix K.
我在下面发布了我的委托示例,以利用list.ForEach。 - MethodMan
2
ForEach 不是扩展方法,也不是 LINQ。ForEachList<T> 上的一个方法。 - cadrell0
是的,但他可以只使用List.ForEach而不是list.Select。 - MethodMan
2
只是提醒一下 - 未来建议您在每个问题/帖子中坚持一个问题。 - Reed Copsey
3个回答

17

为什么result.Add(value)没有被执行?

这是因为LINQ使用延迟执行。直到你枚举结果(即Select的返回值),委托才会执行。

为了说明这一点,请尝试以下操作:

List<int> result = new List<int>();

var list = new List<int> { 1, 2, 3, 4 };

var results = list.Select(value =>
    {
        result.Add(value);//Does not work??
        return value;
    });

foreach(var item in results)
{
     // Just iterating through this will cause the above to execute...
}

话虽如此,这是一个不好的想法。如果可能的话,LINQ查询不应该有副作用。将Select视为转换数据的方式,而不是执行代码的方式。

然而,如果不执行此操作,是否有方法可以使用扩展方法在IEnumerable上进行foreach循环?

您可以编写自己的扩展方法:

public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    foreach(var item in items)
         action(item);
}

然而,我建议不要这样做。有关详细信息,请参阅Eric Lippert关于此主题的帖子


谢谢你的回答,你的描述解决了我对IEnumerable和延迟执行的困惑。 - Reza ArabQaeni

3

Select是一个懒加载函数,执行被延迟到你开始枚举结果时才会进行。你需要通过调用.ToArray或循环遍历结果来消耗结果集:

list.Select(value =>
    {
        result.Add(value);//Does not work??
        return value;
    }).ToArray();

如果我要使用一种方法来强制枚举,我会选择一个具有恒定内存的方法,比如Max()而不是ToArray() - Jon Hanna

-1
List<int> result = new List<int>();
var list = new List<int> { 1, 2, 3, 4 };
list.ForEach(delegate(int sValue)
{
    result.Add(sValue);
});

这个可以工作,但是会把1、2、3、4都加入到结果中。试一下吧,我刚刚试过了。


我提到过:除了这种方式:IEnumerable.ToList().Foreach(p=>...) - Reza ArabQaeni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接