我想在LINQ中执行以下操作,但是我不知道如何操作:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
真正的语法是什么?
ForEach
扩展名。
foreach (var i in items) i.Dostuff();
我想在LINQ中执行以下操作,但是我不知道如何操作:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
真正的语法是什么?
ForEach
扩展名。
foreach (var i in items) i.Dostuff();
Answers:
没有ForEach扩展IEnumerable
;只为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);
}
}
IENumerable<T>
在扩展方法中返回。喜欢:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Fredrik提供了此修复程序,但值得一提的是为什么它不在框架之内。我相信LINQ查询运算符应该是无副作用的,并且适合以合理的方式查看世界。显然,ForEach正好相反- 纯粹是基于副作用的构造。
这并不是说这是一件坏事,只是想想这个决定背后的哲学原因。
Seq.iter
不返回任何内容,更不用说带有侧面影响元素的新序列了。这实际上只是副作用。您可能会想到Seq.map
,因为Seq.iter
它完全等效于上的ForEach
扩展方法IEnumerabe<_>
。
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()));
}
您可以使用FirstOrDefault()
扩展名,该扩展名可用于IEnumerable<T>
。通过false
从谓词返回,它将为每个元素运行,但不在乎它实际上没有找到匹配项。这样可以避免ToList()
开销。
IEnumerable<Item> items = GetItems();
items.FirstOrDefault(i => { i.DoStuff(); return false; });
foreach(Item i in GetItems()) { i.DoStuff();}
您带了更多的角色并使之极为混乱
items.All(i => { i.DoStuff(); return true; }
我采用了Fredrik的方法并修改了返回类型。
这样,该方法像其他LINQ方法一样支持延迟执行。
编辑:如果尚不清楚,则此方法的任何用法都必须以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枚举。
ForEach
很有趣,但是与List.ForEach
的签名不匹配的行为不匹配public void ForEach(Action<T> action)
。它也不符的行为Observable.ForEach
扩展IObservable<T>
,签名,其中是public static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
。FWIW,与ForEach
Scala集合等效,即使是那些懒惰的集合,也具有返回类型,该返回类型等效于C#中的void。
Select
同ToList
。的目的ForEach
是不必致电ToList
。它应该立即执行。
我想在LINQ中执行以下操作,但是我不知道如何操作:
正如其他人在国内外所指出的那样,LINQ和IEnumerable
方法有望实现无副作用。
您是否真的要对IEnumerable中的每个项目执行“操作”?然后foreach
是最佳选择。当这里发生副作用时,人们并不感到惊讶。
foreach (var i in items) i.DoStuff();
但是根据我的经验,通常不需要副作用。Jon Skeet,Eric Lippert或Marc Gravell常常会解释一个简单的LINQ查询,并等待StackOverflow.com的回答,解释如何做自己想做的!
如果您实际上只是在汇总(累加)某个值,则应考虑Aggregate
扩展方法。
items.Aggregate(initial, (acc, x) => ComputeAccumulatedValue(acc, x));
也许您想IEnumerable
根据现有值创建一个新值。
items.Select(x => Transform(x));
或者,也许您想创建一个查找表:
items.ToLookup(x, x => GetTheKey(x))
可能性的清单(并非完全是双关语)不断出现。
如果要充当枚举卷,则应产生每个项目。
public static class EnumerableExtensions
{
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
{
foreach (var item in enumeration)
{
action(item);
yield return item;
}
}
}
Microsoft提供了一个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));
根据PLINQ(自.Net 4.0起可用),您可以执行
IEnumerable<T>.AsParallel().ForAll()
在IEnumerable上执行并行的foreach循环。
很多人提到它,但是我不得不写下来。这不是最清晰/最易读的吗?
IEnumerable<Item> items = GetItems();
foreach (var item in items) item.DoStuff();
简短而简单。
GetItems()
方法返回。
foreach (var item in GetItems()) item.DoStuff();
只是一种美。
现在我们可以选择...
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = 4;
#if DEBUG
parallelOptions.MaxDegreeOfParallelism = 1;
#endif
Parallel.ForEach(bookIdList, parallelOptions, bookID => UpdateStockCount(bookID));
当然,这打开了一个全新的线程蠕虫罐。
ps(对不起字体,这是系统决定的)
正如许多答案所指出的那样,您可以轻松地自己添加这样的扩展方法。但是,如果您不想这样做,尽管我不了解BCL中的类似信息,但System
如果您已经引用了Reactive Extension(并且如果您没有, 你应该有):
using System.Reactive.Linq;
items.ToObservable().Subscribe(i => i.DoStuff());
尽管方法名称有所不同,但最终结果正是您要寻找的。
ForEach也可以被Chained,只需在动作后放回桩线即可。保持流利
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
}
编辑:一个懒惰的版本使用屈服的回报,像这样。
public static IEnumerable<T> ForEachLazy<T>(this IEnumerable<T> enu, Action<T> action)
{
foreach (var item in enu)
{
action(item);
yield return item;
}
}
懒惰的版本需要被物化,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()都保留在我的库中。
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
?单个显式循环。我想在开始执行action2之前执行所有 action1 是否重要。
ProcessShipping()
怎么办?您向买家发送电子邮件,从他的信用卡中扣款,但从不向他发送东西吗?当然要问问题。
这种“功能方法”的抽象会浪费大量时间。语言层面上没有任何东西可以防止副作用。只要您可以使其对容器中的每个元素都调用lambda / delegate-您将获得“ ForEach”行为。
例如,这里将srcDictionary合并到destDictionary中的一种方法(如果密钥已经存在-覆盖)
这是一个hack,不应在任何生产代码中使用。
var b = srcDictionary.Select(
x=>
{
destDictionary[x.Key] = x.Value;
return true;
}
).Count();
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
吗?如果不在生产代码中,那么为什么在何处使用此代码?
受乔恩·斯基特(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);
}
Linq有 IEnumerable<T>.ForEach
很多其他有用的扩展。仅仅为了获得依赖可能不值得ForEach
,但其中有很多有用的东西。
我尊重不同的观点,即链接扩展方法应无副作用(不仅因为它们不是,任何委托都可以执行副作用)。
考虑以下:
public class Element {}
public Enum ProcessType
{
This = 0, That = 1, SomethingElse = 2
}
public class Class1
{
private Dictionary<ProcessType, Action<Element>> actions =
new Dictionary<ProcessType,Action<Element>>();
public Class1()
{
actions.Add( ProcessType.This, DoThis );
actions.Add( ProcessType.That, DoThat );
actions.Add( ProcessType.SomethingElse, DoSomethingElse );
}
// Element actions:
// This example defines 3 distict actions
// that can be applied to individual elements,
// But for the sake of the argument, make
// no assumption about how many distict
// actions there may, and that there could
// possibly be many more.
public void DoThis( Element element )
{
// Do something to element
}
public void DoThat( Element element )
{
// Do something to element
}
public void DoSomethingElse( Element element )
{
// Do something to element
}
public void Apply( ProcessType processType, IEnumerable<Element> elements )
{
Action<Element> action = null;
if( ! actions.TryGetValue( processType, out action ) )
throw new ArgumentException("processType");
foreach( element in elements )
action(element);
}
}
该示例显示的实际上只是一种后期绑定,它允许一个调用对元素序列产生副作用的许多可能的动作之一,而不必编写大型的switch构造来解码定义该动作并转换的值将其转换为相应的方法。
另一个ForEach
例子
public static IList<AddressEntry> MapToDomain(IList<AddressModel> addresses)
{
var workingAddresses = new List<AddressEntry>();
addresses.Select(a => a).ToList().ForEach(a => workingAddresses.Add(AddressModelMapper.MapToDomain(a)));
return workingAddresses;
}
ForEach()
。