在使用C#中的文件时,我习惯于考虑释放相关资源.通常这是一个using语句,除非它是像File.ReadAllLines这样的单行内容方法,它将为我打开和关闭文件.
.Net 4.0引入了方便的File.ReadLines方法.这将返回一个IEnumerable,并被视为一种更有效的方法来处理文件 - 它避免将整个文件存储在内存中.为此,我假设枚举器中有一些延迟执行逻辑.
显然,因为这个方法返回一个IEnumerable,而不是IDisposable,我不能用我对使用语句的直觉反应.
我的问题是:考虑到这一点,使用此方法是否存在资源释放的问题?
调用此方法是否意味着关联文件锁的释放是不确定的?
ang*_*son 17
IEnumerable不会从IDisposable继承,因为通常,实现它的类只会给你可枚举的承诺,它实际上没有做任何可以处理的事情.
但是,当您枚举它时,首先IEnumerator通过调用IEnumerable.GetEnumerator方法来检索,通常,您获取的基础对象确实实现了IDisposable.
的方式foreach实现与此类似:
var enumerator = enumerable.GetEnumerator();
try
{
// enumerate
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
disposable.Dispose();
}
Run Code Online (Sandbox Code Playgroud)
这样,如果对象确实实现了IDisposable,它将被处理掉.因为File.ReadLines,在你开始枚举文件之前,文件并没有真正打开,所以你得到的对象File.ReadLines不需要处理,但是你得到的枚举器就是这样.
正如评论所指出的IEnumerator那样IDisposable,即使许多典型的实现都没有继承,但泛型IEnumerator<T>确实继承了IDisposable.
+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;
}
Run Code Online (Sandbox Code Playgroud)