File.ReadLines何时释放资源

在使用C#中的文件时,我习惯于考虑释放相关资源。 通常这是一个using语句,除非它是像File.ReadAllLines这样的单行内容方法,它将为我打开和关闭文件。

.Net 4.0引入了方便的File.ReadLines方法。 这将返回一个IEnumerable,并被视为一种更有效的方式来处理文件 – 它避免将整个文件存储在内存中。 为此,我假设枚举器中有一些延迟执行逻辑。

显然,因为这个方法返回一个IEnumerable,而不是IDisposable,我不能用我对使用语句的直觉反应。

我的问题是:考虑到这一点,使用此方法是否存在资源释放的问题?

调用此方法是否意味着关联文件锁的释放是不确定的?

IEnumerable不会从IDisposableinheritance,因为通常,实现它的类只能为您提供可枚举的承诺 ,它实际上还没有做任何可以处理的事情。

但是,当您枚举它时,首先通过调用IEnumerable.GetEnumerator方法来检索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并不inheritance自IDisposable ,即使许多典型的实现都是如此,而通用的IEnumerator确实inheritance了IDisposable

Lasse的回答是+1。

特别是对于枚举器调用.MoveNext()File.ReadLines ,当遇到EOF或发生故障时,内部TextReader将被丢弃。

 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.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.5__1; this.<>1__state = 2; return true; Label_005C: if ((this.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; }