Foreach、扩展方法和 IEnumerable

Foreach, extension methods, and IEnumerable

只是出于好奇而快速提问。因此,根据有关 foreach 循环的 MSDN 文档,它实现了 System.Collections.IEnumerable。文档中还有一个警告,您不能在使用 foreach 循环时修改集合(我假设 foreach 循环在这方面不是线程安全的?)

文档https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in

另外,出于好奇,就速度而言,foreach 循环是否比for 循环更优化?我知道 foreach 循环更容易 type/read,但它比 for 循环执行得更快吗?

查看MSDN文档中的一个列表,扩展方法Average是由Enumerable定义的。当文档说它对每个元素执行转换功能时,文档是什么意思? 这是否意味着扩展方法的行为类似于 foreach 循环? 文档https://msdn.microsoft.com/en-us/library/bb549067(v=vs.110).aspx

假设地说,假设我有两个线程。假设我有一个由这两个线程共享的列表。第一个线程遍历此列表 (foreach),第二个线程在此列表上使用 Average 扩展方法。那么这样会不会导致抛出异常呢?我知道使用锁可以避免任何潜在的问题,但为了便于讨论,我们假设我没有使用锁。

感谢您的宝贵时间。

So according to the MSDN documentation regarding foreach loop, it implements System.Collections.IEnumerable

没有。任何支持 GetEnumerator() 方法的东西反过来 returns 支持 bool MoveNext() 方法和 Current 属性 的对象将支持 foreachIEnumerableIEnumerable<T> 都支持这一点,因此实现它们的所有内容都将允许 foreach,但这不是唯一的方法。这不仅是一种方便的方法,而且是一种可以与采用 IEnumerable<T> 的方法(包括 linq 扩展方法)一起使用的方法,因此当您想要支持 foreach 时,通常最好采用这种方法. (您可能会选择 支持另一种方式,就像 List<T> 那样,但很少值得这样做。

Also, out of curiosity, is a foreach loop more optimized than a for loop in terms of speed?

这很复杂,因为这是 foreachfor 的问题。 for 具有优势是很常见的,因为它涉及较少的虚拟调用,但当 foreach 更快时也有例外。为了增加复杂性,如果你直接作用于一个数组,那么 foreach 会更慢,除非编译器实际捕获它并在幕后为你将它重写为 for 所以它们完全相同。

What does the documentation mean when it says it performs a transform function on each element.

这意味着 Average 的特定重载将每个元素传递给对传递给它的 selector 的调用。就是这个transform的结果被平均了。

Does this mean the extension method behaves similarly to a foreach loop?

是的。事实上,他们经常 foreach。该特定方法是 .NET Framework 版本中的 foreach 和 .NET Core 版本中 foreach 的轻微优化。许多方法在两个版本中都是 foreach。某些方法在已知性能更高的少数情况下使用 for(请参阅上文,了解有时是这种情况,有时不是)。在绝大多数情况下,所做的大部分优化都是不值得的,但是 Linq 方法被很多人大量使用,因此即使是一点点优化的努力也会得到回报。

The first thread is traversing through this list (foreach) and the second thread is using the Average extension method on this list. So will this cause an exception to be thrown?

在这种特殊情况下,只要没有线程写入列表,两者就不会互相造成任何问题。用于实现 foreach 的对象是在每个线程中单独创建的,它们是唯一会发生变化的对象。 List<T> 的文档不保证这一点,但不太可能更改。

但这并不适用于支持 foreach 的所有内容。 multi-threaded foreach 周围没有任何承诺,除非给定的实现做到了。