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
.