2010-07-31 39 views
8

當在C#中處理文件時,我有條件考慮釋放相關資源。通常這是一個使用語句,除非它像File.ReadAllLines這樣的單行便利方法 ,它將爲我打開和關閉文件。什麼時候File.ReadLines免費資源

.net 4.0引入了方便的方法File.ReadLines。這將返回一個IEnumerable,並被視爲處理文件的更有效方式 - 避免將整個文件存儲在內存中。爲此,我假設枚舉器中存在一些延遲執行邏輯。

很明顯,因爲這個方法返回一個IEnumerable,而不是和IDisposable,我不能用我使用using語句的直覺反應。

我的問題是: 考慮到這一點,是否有任何資源釋放這個方法的陷阱?

調用此方法是否意味着相關文件鎖定的釋放是非確定性的?

回答

12

IEnumerable不自IDisposable繼承,因爲通常情況下,實現它的類只給你的是枚舉的承諾,它實際上並沒有做任何事情權證處置。

但是,當您枚舉它,你首先通過調用IEnumerable.GetEnumerator方法檢索IEnumerator,典型的是底層的對象,你回來實現IDisposable

的實現方式foreach與此類似:

var enumerator = enumerable.GetEnumerator(); 
try 
{ 
    // enumerate 
} 
finally 
{ 
    IDisposable disposable = enumerator as IDisposable; 
    if (disposable != null) 
     disposable.Dispose(); 
} 

這樣一來,如果對象確實實現IDisposable,它將被處置。對於File.ReadLines,只有在開始枚舉該文件之後,該文件纔會真正打開,因此從File.ReadLines獲得的對象不需要進行處理,而是可以使用枚舉器。

正如評論指出,IEnumerator不從IDisposable繼承,儘管許多典型的實現呢,而通用IEnumerator<T>不繼承IDisposable

+0

實際上,IEnumerator並沒有實現IDisposable。但IEnumerator的許多*實現確實實現了IDisposable,foreach循環和LINQ擴展方法都是通過''''''來查看枚舉器是否實現了IDisposable,如果是,則調用Dispose。 – 2010-07-31 18:14:20

+2

更正:非泛型IEnumerator不實現IDisposable,但是泛型('IEnumerator ')。 – 2010-07-31 18:15:15

+0

啊,你說得對。嘎,愚蠢的錯誤,讓我編輯答案。 – 2010-07-31 18:15:20

2

+1爲Lasse的答案。

特別是對於File.ReadLines,其中調查員調用.MoveNext()時,內部TextReader將在遇到EOF或出現故障時處置。

private bool MoveNext() 
{ 
    bool flag; 
    try 
    { 
     switch (this.<>1__state) 
     { 
      case 0: 
       this.<>1__state = -1; 
       this.<>7__wrap2 = this.reader; 
       this.<>1__state = 1; 
       this.<line>5__1 = null; 
       goto Label_005C; 

      case 2: 
       this.<>1__state = 1; 
       goto Label_005C; 

      default: 
       goto Label_0078; 
     } 
    Label_003E: 
     this.<>2__current = this.<line>5__1; 
     this.<>1__state = 2; 
     return true; 
    Label_005C: 
     if ((this.<line>5__1 = this.reader.ReadLine()) != null) 
     { 
      goto Label_003E; 
     } 
     this.<>m__Finally3(); // Disposal at end of file. 
    Label_0078: 
     flag = false; 
    } 
    fault 
    { 
     this.System.IDisposable.Dispose(); // Disposal due to fault. 
    } 
    return flag; 
}