在没有ToList()的情况下运行时,在Linq的SelectMany()中读取文件会抛出System.IO.IOException

时间:2017-12-20 10:31:07

标签: c# linq io

我很好奇为什么下面一段代码因System.IO.IOException而失败,说该进程无法访问该文件,因为它正被另一个进程使用。

class Program
{
    static void Main(string[] args)
    {
        const string filename = "tmp.txt";
        File.AppendAllText(filename, "x");
        var output = Enumerable.Range(0, 10).SelectMany(_ => File.ReadAllLines(filename));
        File.WriteAllLines(filename, output);
    }
}

只需在Linq Pipeline的末尾抛出一个ToList(),我就可以避免这个问题,但我无法弄清楚为什么会出现这种情况。

2 个答案:

答案 0 :(得分:4)

您会看到Linq laziness 实现的效果。

添加.ToList()后,我们output 具体化 Linq 执行查询(打开文件,填写集合和关闭文件):

 // List<T> collection
 var output = Enumerable
   .Range(0, 10)
   .SelectMany(_ => File.ReadAllLines(filename))
   .ToList();  // <- We want a collection in memory

所以在写的时候,我们从内存中写入数据做磁盘

 // Writing down the collection
 File.WriteAllLines(filename, output);

没有.ToList() Linq( lazy nothing

 // IEnumerable<T> 
 var output = Enumerable
   .Range(0, 10)
   .SelectMany(_ => File.ReadAllLines(filename)); // <- No more than a declaration

什么时候写

 File.WriteAllLines(filename, output);

Linq 发现它必须提供应该写入的数据 - output并开始执行此操作:它尝试打开文件但是失败了此操作,因为文件已使用File.WriteAllLines打开。

答案 1 :(得分:0)

因为您试图同时读取和写入同一文件,

ToList()导致执行(枚举)在此时发生,其中SelectMany返回IEnumerable并等待其执行(枚举)File.WriteAllLines(filename, output)