IEnumerable <T>的foreach相当于LINQ

我想在LINQ中进行如下操作,但我无法弄清楚:

IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());

什么是真正的语法?


IEnumerable没有ForEach扩展; 仅用于List<T> 。 所以你可以做

items.ToList().ForEach(i => i.DoStuff());

或者,编写您自己的ForEach扩展方法:

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

弗雷德里克提供了这个修复,但它可能值得考虑为什么这不是在框架开始。 我相信这个想法是,LINQ查询操作符应该是无副作用的,适合于查看世界的合理功能的方式。 很明显ForEach正好相反 - 一个纯粹的基于副作用的构造。

这并不是说这是一件坏事,只是想着决定背后的哲学原因。


2012年7月17日更新 :显然,从C#5.0开始,下面描述的foreach行为已经发生了变化,“在嵌套lambda表达式中使用foreach迭代变量不再会产生意外的结果。” 此答案不适用于C#≥5.0。

@John Skeet和喜欢foreach关键字的每个人。

5.0之前的 C#中的“foreach”的问题在于它与其他语言中等效的“理解”是如何工作的以及我期望它如何工作是不一致的(个人认为这里仅仅是因为其他人提到了它们关于可读性的意见)。 查看所有关于“访问修改的关闭”以及“关闭被认为有害的循环变量”的问题。 由于在C#中实现“foreach”的方式,这只是“有害的”。

以@Fredrik Kalseth的答案中的功能等效扩展方法为例。

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

为过分设想的例子道歉。 我只使用Observable,因为它并不是完全可以用来做这样的事情。 显然有更好的方法来创建这个可观察的,我只是试图展示一个观点。 通常,订阅observable的代码是异步执行的,可能在另一个线程中执行。 如果使用“foreach”,这可能会产生非常奇怪的和潜在的非确定性结果。

以下使用“ForEach”扩展方法的测试通过:

[Test]
public void ForEachExtensionWin()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                values.ForEach(value => 
                                    source.OnNext(() => value));

                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Win
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}

以下失败并出现错误:

预期:相当于<0,1,2,3,4,5,6,7,8,9>但是:<9,9,9,9,9,9,9,9,9,9>

[Test]
public void ForEachKeywordFail()
{
    //Yes, I know there is an Observable.Range.
    var values = Enumerable.Range(0, 10);

    var observable = Observable.Create<Func<int>>(source =>
                            {
                                foreach (var value in values)
                                {
                                    //If you have resharper, notice the warning
                                    source.OnNext(() => value);
                                }
                                source.OnCompleted();
                                return () => { };
                            });

    //Simulate subscribing and evaluating Funcs
    var evaluatedObservable = observable.ToEnumerable().Select(func => func()).ToList();

    //Fail
    Assert.That(evaluatedObservable, 
        Is.EquivalentTo(values.ToList()));
}
链接地址: http://www.djcxy.com/p/1523.html

上一篇: LINQ equivalent of foreach for IEnumerable<T>

下一篇: How do you get the index of the current iteration of a foreach loop?