2013-11-21 85 views
58

有時ReSharper的警告一下:IEnumerable的ReSharper的示例代碼

可能多個枚舉

an SO question on how to handle this issue,並ReSharper的網站也解釋了事情here。它有一些示例代碼,告訴你這樣做,而不是:

IEnumerable<string> names = GetNames().ToList(); 

我的問題是關於這個具體建議:不會這還導致通過集合中的2-每個循環枚舉兩次?

回答

146

GetNames()返回IEnumerable。所以,如果你存儲結果:

IEnumerable foo = GetNames(); 

然後每次枚舉foo時,GetNames()方法再次被調用(不誇張地說,我無法找到一個鏈接,正確解釋的細節,但看到IEnumerable.GetEnumerator())。

ReSharper的看到了這一點,並通過在列表中去實現它建議你存儲在一個局部變量枚舉GetNames(),例如的結果

IEnumerable fooEnumerated = GetNames().ToList(); 

這將確保該GetNames()結果只列舉一次,只要你參考fooEnumerated

這件事情確實是因爲你通常要一次列舉,例如當GetNames()執行(慢)數據庫調用。

因爲你物化結果在列表中,你再次列舉fooEnumerated兩次都沒關係;您將兩次遍歷內存列表。

+0

啊可能的多個枚舉!這解釋了它。 – user2250250

+0

否。只有在foreach循環中調用GetEnumerator()方法一次。真正的原因是髒數據的風險。例如,在GetNames()中,有一個SQL查詢,但只有返回IEnurable的查詢。當調用.ToList()時,將所有數據存儲在內存中,髒數據的風險很小。但是如果在2次循環之間有很多時間,如果每次都對數據庫執行SQL,那麼髒數據的風險很大。 –

+0

@SunRobin這是一個以簡化形式呈現真相的答案,正如也在其中提到的那樣。我還沒有到處去改進它。您使用「髒數據」可能需要進一步解釋。 – CodeCaster

4

是的,你會毫無疑問地列舉兩次。但問題是,如果GetNames()返回一個懶惰的LINQ查詢這是計算則非常昂貴,將計算兩次沒有到ToList()ToArray()通話。

7

GetNames()不會被調用兩次。每次您想要使用foreach來枚舉集合時,都會調用IEnumerable.GetEnumerator()的實現。如果在IEnumerable.GetEnumerator()內進行了一些昂貴的計算,這可能是一個需要考慮的原因。