我想在 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);
}
}
Fredrik 提供了修复程序,但是可能值得考虑为什么它不在框架之内。我相信 LINQ 查询运算符应该是无副作用的,并以合理的功能来看待世界。显然,ForEach 正好相反 -纯粹基于副作用的构造。
这并不是说这是一件坏事,只是想想这个决定背后的哲学原因。
2012 年 7 月 17 日更新:显然,从 C#5.0 版本开始,以下所述的foreach
行为已更改,并且 “在嵌套 lambda 表达式中使用foreach
迭代变量不再产生意外结果。 ” 此答案不适用于 C# ≥5.0。
@John Skeet 和每个喜欢 foreach 关键字的人。
5.0 之前的C#中的 “foreach” 的问题在于,它与其他语言中的 “for comprehension” 的工作方式以及我希望它的工作方式不一致(个人之所以在此陈述是因为其他人提到了他们的关于可读性的意见)。请参阅有关 “访问修改后的闭包” 以及 “ 关闭认为有害的循环变量” 的所有问题。这只是 “有害”,因为在 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,因为要做这样的事情并不遥不可及。显然,有更好的方法来创建此可观察的对象,我只是在尝试说明一个观点。通常,预订可观察对象的代码是异步执行的,并且有可能在另一个线程中执行。如果使用 “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>
[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()));
}