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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在没有ToList()的情况下运行时,在Linq的SelectMany()中读取文件会抛出System.IO.IOException相关的知识,希望对你有一定的参考价值。

我很好奇为什么下面的代码失败了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管道的末端抛出一个ToList(),我避免了这个问题,但我无法弄清楚为什么会这样。

答案

你看到了Linq懒惰和物化的影响。

随着.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(懒惰)什么都不做:

 // 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打开。

另一答案

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

ToList()导致执行(枚举)发生在那一点,SelectMany返回一个IEnumerable并等待它在File.WriteAllLines(filename, output)执行(枚举)

以上是关于在没有ToList()的情况下运行时,在Linq的SelectMany()中读取文件会抛出System.IO.IOException的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 Linq 的情况下从列表中获取一些对象?

linq 和lambda查询

如何使用LINQ C#更新数据表中的datarow?

Linq 得到条件计数

LINQ使用与并行

有没有办法在没有 Linq to Entities 的情况下使用 SqlSpatialFunctions?