【问题标题】:Are files opened by File.ReadLine closed on exceptions?File.ReadLine 打开的文件是否因异常而关闭?
【发布时间】:2015-01-22 11:14:20
【问题描述】:

如果在迭代生成的可枚举时引发异常,是否会关闭通过 File.ReadLines 读取的文件?

例子:

File.ReadLines("file.txt")
    .Select(line => { throw new Exception(); return 1; });

file.txt 曾经关闭吗?

而如果确实是关闭的,那迭代不会继续的事实怎么会由实现来决定呢?

我无法理解如何关闭文件的原因如下。我怀疑ReadLines 的实现是这样的:

IEnumerable<string> ReadLines(string file)
{
    using (var reader <Open reader>)
    {
        String line = null;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    } 
}

如果在迭代期间抛出异常,则不会从生成的枚举器中获取所有行。然后在while-statement 之后的行永远不会到达并且using-statement 将没有机会关闭流。

【问题讨论】:

  • 为什么不关闭文件? using 语句使用 finally,因此无论异常如何都会被处理
  • 但是while循环只有在所有行都被读取后才会终止。除非客户端使用生成的枚举器实际完成迭代,否则情况并非如此。如果在迭代期间抛出异常,则枚举器不会获取某些元素,并且 while 循环不应终止。
  • 你需要查看Select 的实现,看看它为什么会被关闭。
  • @JamesBarrass 1) 这是一个迭代器,所以finally 语句与普通的finally 语句完全不同。 finally 语句在迭代器到达末尾(对于 OP 永远不会发生)或迭代器被释放时执行。如果处置没有发生,则关闭文件将延迟到迭代器的终结器,如果有的话,它可能会运行得更晚。 2) always 很强大,有一堆情况,其中大多数涉及强制进程终止而不执行。
  • @CodesInChaos,是的,在某些情况下 finally 语句没有被执行,但我认为它们与问题无关,可能不应该让它变得粗体。 1) 我很感兴趣,所以我来调查一下!

标签: c# .net io


【解决方案1】:

当使用foreach 的枚举被中止时,枚举数被释放。在这种“提前处置”的情况下,C# 迭代器方法会执行所有活动的 finally 块。这意味着迭代器方法中的所有using 语句都将被执行,因为using 是基于finally

为了更具体:Dispose 只能在 C# 生成的枚举器的 yield return 语句中调用。只有yield return 将控制权交给调用者。

生成的状态机在每个屈服点跟踪最终块处于活动状态,并在Dispose 方法中执行它们。

如果您只是简单地放弃枚举器 (File.ReadLines("file.txt").GetEnumerator();),最终块将不会被执行。没有机制可以做到这一点。

TL;DR:只要您处理最外层的枚举器和链中​​的所有枚举器(此处为:SelectReadLines),文件就会在所有情况下都被关闭,使用finally 正确处理它们的内部枚举器。

【讨论】:

  • 啊,finally-blocks 在处理枚举数的迭代方法中,这是有道理的!谢谢!
  • 这确实提示在使用自己的可枚举横向方法以避免文件打开时要小心。
  • @Lii 如果您使用 foreach 或将所有 IEnumerator 包含在使用中,所有这些都会自动工作。无论如何,这是推荐的。
  • 啊,我明白了!这是关于这个主题的blog post
【解决方案2】:

是的,它将被关闭。它在内部通过 FileStream 创建一个 StreamReader 并在 using 块中使用它。 我不确定你在第二个问题中的意思(你可以简单地捕捉到异常)。

【讨论】:

  • 我不认为这个答案很有帮助,因为操作员的处置以及 finally 语句的执行是由 OP 甚至没有发布的代码触发的(使用枚举器的代码通过在 Select 的结果上调用 GetEnumerator() 返回)。
猜你喜欢
  • 2017-12-09
  • 1970-01-01
  • 2016-09-10
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多