2012-07-04 103 views
11

想知道爲什麼Enumerable.Range實現了IDisposableEnumerable.Range爲什麼實現IDisposable?

我明白爲什麼IEnumerator<T>可以,但IEnumerable<T>並不需要它。


(我發現這一點,而我.Memoise()的實現,它像

if (enumerable is IDisposable) 
    ((IDisposable)enumerable).Dispose(); 
在其「源結束」的方法

,我已經放在出於好奇斷點聲明玩,並通過測試觸發。)

+1

http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx –

回答

7

Enumerable.Range在其方法體中使用yield return。該yield return語句產生實現IDisposable匿名類型,編譯器的魔力下,像這樣:

static IEnumerable<int> GetNumbers() 
{ 
    for (int i = 1; i < 10; i += 2) 
    { 
     yield return i; 
    } 
} 

編譯後,有一個匿名的嵌套類是這樣的:

[CompilerGenerated] 
private sealed class <GetNumbers>d__0 
    : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable 
{ 
    //the implementation 
    //note the interface is implemented explicitly 
    void IDisposable.Dispose() { } 
} 

所以結果is a IDisposable。在這個例子中,Dispose方法留空。我認爲原因是沒有必要處理。如果您的yield return包含非託管資源的類型,您可能會得到不同的編譯結果。 (不確定)

+0

編譯器是否實現了IEnumerable和IEnumerator同一個類?有趣。我必須考慮那些作品。 – Fowl

+0

哦,我現在看到它。它使用它的狀態機來檢測GetEnumerator是否被多次調用,如果沒有,則返回自身。 – Fowl

+0

這是有道理的,但是當工廠的返回類型看起來不是反模式時,有一個工廠方法返回一個實現'IDisposable'的類型。通過'yield return'生成的編譯器生成的迭代器看起來似乎是沒有處置的放棄實際上是無害的類型,前提是從未調用過GetEnumerator(),但是一旦調用了GetEnumerator(),就一定需要處置。順便說一句,在GetEnumerable()之後的迭代器上調用Dispose至少會被調用一次將使第一個枚舉器無效。 – supercat

相關問題