2013-01-07 50 views
20

我有一個關於延遲執行和數據處理的問題。在「using」語句中使用yield時,Dispose何時發生?

請看下面的例子:

private IEnumerable<string> ParseFile(string fileName) 
{ 
    using(StreamReader sr = new StreamReader(fileName)) 
    { 
     string line; 
     while((line = sr.ReadLine()) != null) 
     { 
      yield return line; 
     } 
    } 
} 

private void LineReader(string fileName) 
{ 
    int counter = 0; 

    foreach(string line in ParseFile(fileName)) 
    { 
     if(counter == 2) 
     { 
      break; // will this cause a dispose on the StreamReader? 
     } else 
     { 
      Console.WriteLine(line); 
      counter++; 
     } 
    } 
} 

請問break聲明立即引起ParseFile讀者處置或仍然在上下文中考慮,並直至程序本身將關閉鎖打開的文件?

+2

編寫一個快速控制檯應用程序,並找出:) – jjxtra

+0

哦一個方面的說明,而不是在計數器命中兩個時使用'break',只需在'ParseFile'的末尾添加一個'Take(2)'。 – Servy

+1

如果您想要對迭代器塊中發生的事情有一個很好的解釋,或者只是查看語言規範,就像他經常暗示的那樣,拿起Jon Skeet的書「C#深入」一書。 –

回答

16

所以我們有幾個單獨的問題在這裏進行。

首先,在迭代器塊中處理usingIEnumerator延伸IDisposable。生成迭代器塊的代碼實際上足夠強大,以至於任何try/finally塊(using導致創建try/finally塊)會導致finally塊的內容在枚舉器的Dispose方法中調用,如果它不是已經呼叫過。所以只要統計員被處置,它就不會泄露StreamReader

所以現在我們問自己,如果統計員被處置。所有foreach報表將在調查員上調用Dispose(應執行IDisposable)。即使您使用breakreturn聲明以及正常結束時退出,他們也會這樣做。

所以你可以肯定的是,在任何情況下,資源都不會泄漏,除非沒有什麼可以防止泄漏(即有人拔出機器)。

+0

這比這更復雜一點。在OP的情況下,迭代器將絕對處置break語句的原因。但是對ParseFile的調用會在現在已超出範圍的「本地使用」內產生對StreamReader的引用。我認爲這會在終結者隊列中排隊並在收集時進行處理? – n8wrl

+3

@ n8wrl不,那是不正確的。當'foreach'循環處理'IEnumerator'時,它會調用'StreamReader'處理(假設它在這個''using'內部)。這是迭代器塊的實現方式;使這樣做成爲可能。 – Servy

+0

我想我們應該採取PsychoDad的建議,並嘗試一下,如果這是它的工作原理,那將是非常酷的! – n8wrl

相關問題