2010-07-31 4 views
8

При работе с файлами на C# я вынужден думать о освобождении связанных ресурсов. Обычно это оператор using, если только он не поддерживает метод однострочного выравнивания , например File.ReadAllLines, который откроет и закроет файл для меня.Когда File.ReadLines освобождает ресурсы

.Net 4.0 ввел удобный метод File.ReadLines. Это возвращает IEnumerable и объявляется как более эффективный способ обработки файла - он позволяет избежать хранения всего файла в памяти. Для этого я предполагаю, что в счетчике есть некоторая отложенная логика выполнения.

Очевидно, так как этот метод возвращает IEnumerable, not и IDisposable, я не могу перейти с моей реакцией на использование выражения.

Мои вопросы: Имея это в виду, есть ли какие-либо проблемы с освобождением ресурсов с помощью этого метода?

Вызов этого метода означает, что освобождение связанных файловых замков не является детерминированным?

ответ

12

IEnumerable не наследуется от IDisposable, так как обычно, класс, который реализует это только дает обещание быть перечислимы, он на самом деле не сделал ничего еще, что распоряжение ордера.

Однако, когда вы перечислить на него, сначала извлечь IEnumerator путем вызова метода IEnumerable.GetEnumerator, и, как правило, основной объект вы получите обратно делает реализовать 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, все делают 'as' cast, чтобы проверить, реализует ли enumerator IDisposable, и если это так, то вызывается Dispose. –

+2

Исправление: не общий IEnumerator не реализует IDisposable, но общий ('IEnumerator '). –

+0

Ах, ты прав. Га, глупая ошибка, позвольте мне отредактировать ответ. –

2

+1 для ответа Лассе.

В частности, для 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; 
} 
Смежные вопросы