2011-07-14 55 views
4

假設SomeMethod具有簽名Foreach Cache IEnumerable?

public IEnumerable<T> SomeMethod<T>(); 

foreach (T tmp in SomeMethod<T>()) { ... } 

IEnumerable<T> result = SomeMethod<T>(); 

foreach (T tmp in result) { ... } 

換句話說之間的差異,將在SomeMethod<T>結果的第一條語句緩存或它會在每次迭代中進行評估嗎?

+1

您可以用所用語言標記問題嗎?這將有助於吸引合格的答覆。 –

回答

13

假設你在談論C#。

foreach轉化爲這樣的事情:

var enumerable = SomeMethod<T>(); // Or whatever is passed to foreach 
var enumerator = enumerable.GetEnumerator(); 

while (enumerator.MoveNext()) 
{ 
... 
} 

所以,enumerable只需要一次,將有隻有一個呼叫,即使你把它直接進入foreach聲明的someMethod。

+2

輕微的狡辯:應該有一個「使用」或「最後」的程序塊,以確保如果枚舉器實現了IDisposable,它將被丟棄。有很多情況,尤其是涉及迭代器的情況,在這種情況下,廢棄的枚舉器可能導致嚴重問題。 – supercat

+0

@supercat:你是對的,但這個例子只是爲了展示foreach的主要概念,而不是用於生產。該foreach本身將負責處理統計員。 –

+2

我知道代碼被設計爲說明性的,但很多人並沒有意識到創建實現IDisposable的枚舉器的代碼必須爲了正確性而確保在調用器上調用Dispose。所有需要確保正確性的事情是在創建枚舉器的前後添加一個「使用」塊。 – supercat

0

enumerATOR通常是與enumerABLE不同類型的對象。通常,枚舉器將持有對可枚舉對象的引用,以及有關枚舉過程中的位置的一些信息。可枚舉對象的目的實際上不是提供一系列的項目,而是提供一個枚舉器,它將依次提供序列。

在vb.net和C#中,foreach構造都是通過在對象上調用一次GetEnumerator方法,並抓取它返回的對象,在從GetEnumerator返回的對象上重複調用MoveNext和Current,最後,如果該對象實現Dispose,調用Dispose。 C#和vb.net實際上都不會緩存可枚舉對象,但它們都不需要在調用GetEnumerator一次之後就將它用於任何目的。兩種語言都支持枚舉器,但除了隱含的對MoveNext,Current和Dispose的調用之外,兩種語言都不提供任何其他方法。

相關問題