我想在LINQ中执行以下等效操作,但我无法确定如何执行:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
真正的语法是什么?
我想在LINQ中执行以下等效操作,但我无法确定如何执行:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
真正的语法是什么?
当前回答
正如许多答案已经指出的那样,您可以自己轻松地添加这样的扩展方法。然而,如果您不想这样做,尽管我不知道BCL中有什么类似的内容,但如果您已经引用了Reactive Extension(如果没有,您应该有),System命名空间中仍然有一个选项:
using System.Reactive.Linq;
items.ToObservable().Subscribe(i => i.DoStuff());
虽然方法名称有点不同,但最终结果正是您所希望的。
其他回答
在Jon Skeet的启发下,我扩展了他的解决方案:
扩展方法:
public static void Execute<TSource, TKey>(this IEnumerable<TSource> source, Action<TKey> applyBehavior, Func<TSource, TKey> keySelector)
{
foreach (var item in source)
{
var target = keySelector(item);
applyBehavior(target);
}
}
客户:
var jobs = new List<Job>()
{
new Job { Id = "XAML Developer" },
new Job { Id = "Assassin" },
new Job { Id = "Narco Trafficker" }
};
jobs.Execute(ApplyFilter, j => j.Id);
...
public void ApplyFilter(string filterId)
{
Debug.WriteLine(filterId);
}
我采用了Fredrik的方法并修改了返回类型。
这样,该方法与其他LINQ方法一样支持延迟执行。
EDIT:如果这一点不清楚,则此方法的任何用法都必须以ToList()或任何其他方式结束,以强制该方法处理完整的可枚举对象。否则,将不会执行该操作!
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (T item in enumeration)
{
action(item);
yield return item;
}
}
下面是帮助您了解它的测试:
[Test]
public void TestDefferedExecutionOfIEnumerableForEach()
{
IEnumerable<char> enumerable = new[] {'a', 'b', 'c'};
var sb = new StringBuilder();
enumerable
.ForEach(c => sb.Append("1"))
.ForEach(c => sb.Append("2"))
.ToList();
Assert.That(sb.ToString(), Is.EqualTo("121212"));
}
如果最后删除ToList(),则会看到测试失败,因为StringBuilder包含一个空字符串。这是因为没有方法强制ForEach枚举。
对于VB.NET,应使用:
listVariable.ForEach(Sub(i) i.Property = "Value")
微软发布了一个LINQ交互扩展的实验版本(也在NuGet上,更多链接请参见RxTeams的简介)。9频道的视频很好地解释了这一点。
它的文档仅以XML格式提供。我在Sandcastle中运行了这个文档,以使其具有更可读的格式。解压缩文档存档并查找index.html。
在许多其他好处中,它提供了预期的ForEach实现。它允许您编写如下代码:
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8 };
numbers.ForEach(x => Console.WriteLine(x*x));
ForEach也可以链接,只需在动作后放回桩线即可。保持流利
Employees.ForEach(e=>e.Act_A)
.ForEach(e=>e.Act_B)
.ForEach(e=>e.Act_C);
Orders //just for demo
.ForEach(o=> o.EmailBuyer() )
.ForEach(o=> o.ProcessBilling() )
.ForEach(o=> o.ProcessShipping());
//conditional
Employees
.ForEach(e=> { if(e.Salary<1000) e.Raise(0.10);})
.ForEach(e=> { if(e.Age >70 ) e.Retire();});
实现的一个版本。
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enu, Action<T> action)
{
foreach (T item in enu) action(item);
return enu; // make action Chainable/Fluent
}
编辑:Lazy版本使用的是收益率返回,如下所示。
public static IEnumerable<T> ForEachLazy<T>(this IEnumerable<T> enu, Action<T> action)
{
foreach (var item in enu)
{
action(item);
yield return item;
}
}
Lazy版本需要具体化,例如ToList(),否则什么都不会发生。请参阅以下ToolmakerSteve的精彩评论。
IQueryable<Product> query = Products.Where(...);
query.ForEachLazy(t => t.Price = t.Price + 1.00)
.ToList(); //without this line, below SubmitChanges() does nothing.
SubmitChanges();
我将ForEach()和ForEachLazy()都保存在库中。