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?