"foreach"和扩展方法的区别:ForEach



有人能指出C#语句和它们相似的扩展方法之间的区别吗?例如:foreach.ForEach(扩展方法)。

如果存在任何差异,它们是什么?安全方面?性能方面?哪一个更好用?哪一个更安全?等

如果没有差异,为什么还要写呢?

我一直在思考和搜索这个问题,如果是我的问题,但没有找到我的答案。

这取决于您使用的扩展方法的实现。在内部,大多数版本的.ForEach.并没有什么特别之处

在应用程序加载和编译时加载扩展方法的时间最短/可以忽略。将.ForEach语法转换为底层ForEach"可能"开销最小,因为它在技术上只是一个包装器。它可能会导致安全问题,但这只是因为它可能会创建关闭位置,在该位置,您的对象可能无法在预期时间收集(例如:在作用域中保存的时间更长)。最终,差别非常非常小,归根结底是味道。当然,除非你试图每一毫秒都剃光,在这种情况下,使用原生身体是最好的方法。

我想提到的是,.ForEach违背了使用lambda语句是纯函数的前提,也就是说,它打破了"函数"风格,并引入了副作用的可能性。使用foreach主体使代码更加可读和明确。

请参阅:为什么IEnumerable上没有ForEach扩展方法?

这是一种折衷。扩展方法当然更简洁,而且它提供了编译时检查。扩展方法还可能带来可读性困难、可维护性困难和副作用。

从这里拍摄

第二个原因是这样做不会增加新的表示语言的力量。这样做可以让你完美地重写清除代码:

foreach(Foo中的Foo){涉及Foo的语句;}

转换为此代码:

foos.ForEach((Foo-Foo)=>{涉及Foo的语句;});

它使用几乎完全相同的字符,但略有不同顺序然而,第二个版本更难理解,更难理解调试,并引入闭包语义,从而可能发生更改对象以微妙的方式生存。

提供的答案不准确。使用ForEach扩展方法时存在许多陷阱。例如,以下扩展方法可能很容易成为性能杀手:

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

然后我们滥用它:

IEnumerable<T> items = new List<T>();
items.ForEach(UpdateItem);

看起来不错,对吧?这里,ForEach()扩展方法是在IEnumerable<T>上调用的,这意味着编译器被迫分配一个泛型枚举器,而不是使用优化的、无分配的版本。然后,Action参数调用另一个相当重的委托分配。将此循环置于热路径上,Garbage Collector将发疯,从而导致严重的性能问题。

请看我的另一个答案,我在其中更详细地解释了这一点。

在安全性方面,我看到开发人员意外地包含了一个第三方程序集来使用特定的ForEach()扩展方法。这意味着从不知从何处以未知的能力运送不需要的依赖。

摘要

  • foreach更安全
  • CCD_ 11的性能更强
  • CCD_ 12较好。编译器确切地知道如何有效地处理它

.ForEach类似于Parallel.ForEach。我以前见过用于开发/调试并行版本的常规.ForEach。它的好处在于,你不必更改一堆代码来在两者之间移动。

一般来说,如果我不想做Parallel.ForEach,那么为了可读性,我更喜欢常规的foreach

最新更新