在"using"语句中使用yield时,何时发生Dispose?

Mid*_*das 21 c# file-io using deferred-execution

我有一个关于延期执行和数据处理的问题.

请考虑以下示例:

private IEnumerable<string> ParseFile(string fileName)
{
    using(StreamReader sr = new StreamReader(fileName))
    {
        string line;
        while((line = sr.ReadLine()) != null)
        {
            yield return line;
        }
    }
}

private void LineReader(string fileName)
{
    int counter = 0;

    foreach(string line in ParseFile(fileName))
    {
        if(counter == 2)
        {
            break; // will this cause a dispose on the StreamReader?
        } else
        {
            Console.WriteLine(line);
            counter++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请问break声明立即引起读者ParseFile处置,或者它仍然在上下文中考虑,并锁定该文件打开,直到程序本身被关闭?

Ser*_*rvy 17

所以我们在这里有几个独立的问题.

首先,处理using迭代器块. IEnumerator延伸IDisposable.生成迭代器块的代码实际上足够健壮,任何try/finally块(using导致try/finally创建块)都会导致在枚举器finallyDispose方法中调用块的内容(如果尚未调用).因此,只要调查员被处置,它就不会泄漏StreamReader.

所以现在我们问自己是否处置了调查员.所有foreach语句都将调用Dispose枚举器(如果它实现IDisposable).即使您使用breakreturn语句退出,以及正常结束时,它们也会这样做.

因此,您可以确保在任何情况下都不会泄露资源,除非可以防止任何事情泄漏(即有人擅自拆除机器).

  • @ n8wrl不,那不是真的.当`IEnumerator`由`foreach`循环处理时,它将调用`StreamReader`上的dispose(假设它在那里的'using`里面).这是迭代器块的实现方式; 使这成为可能. (3认同)
  • 试图找到具体的报价,但你可以开始阅读,以防你更快到达那里.http://blogs.msdn.com/b/ericlippert/archive/2009/07/16/iterator-blocks-part-three-why-no-yield-in-finally.aspx很确定它是最相关的或者七个系列之后的那一个. (3认同)