在IEnumerable迭代一次后,无法从关闭的textreader中读取

本文关键字:读取 textreader 迭代 IEnumerable 一次 | 更新日期: 2023-09-27 18:14:09

我有一个问题,"不能从一个关闭的文本阅读器"异常。我有一个程序,它应该从文件中获取数据,然后用它做一些有趣的事情,得到所有东西的时间跨度。

首先在一个函数中,我正在加载数据:

IEnumerable<string> SomeVariable;
SomeVariable = (from _Something in File.ReadLines(@"file location") select _Something.Split(' ')[1] );

在第二个函数中,我遍历它一次:

foreach (var _Something in SomeVariable)
{
    SomeList.Add(_Something);
}

然而,在第三个函数中,当我试图再次运行它时:

foreach (var _Something in SomeVariable)
{
    SomeOtherList.Add(_Something);
}

我得到异常:不能从一个关闭的textreader中读取。看起来在一次枚举之后,不再可能遍历somvariable。

这是IEnumerable本身的问题,还是与File有关?readline函数?我觉得每次我想遍历它时都从文件中重新加载数据是非常愚蠢的…

p。我做了研究,我意识到解决方案之一是把两个动作放在一个函数中,但不幸的是,这是大学程序,我必须这样写——我必须得到两个动作的单独时间跨度。

在IEnumerable迭代一次后,无法从关闭的textreader中读取

虽然您已经有了一个解决方法:当您忘记Dispose()枚举器时,可能会发生这种情况,从而提示程序中的其他地方存在错误。

下面是一小段代码,它可靠地为我在第二个foreach上抛出一个异常:

var lines = File.ReadLines(@"<...>");
var enumerator = lines.GetEnumerator();
foreach (var line in lines) { }
foreach (var line in lines) { }

是的,这将工作,如果你使用File.ReadAllLines(...)代替,也如果你使用File.ReadLines(...).Select(...).ToList()。然而,这不是一个完整的解决方案:异常的原因是enumerator实现了IDisposable,但是代码忘记了处理它。

var lines = File.ReadLines(@"<...>");
using (var enumerator = lines.GetEnumerator()) { } // <--- using statement
foreach (var line in lines) { }
foreach (var line in lines) { }

您应该找出代码中发生的地方,并以类似的方式修复它。问题不在你所展示的代码中。

您当然可以确保只读取文件一次。但是你应该把它和你得到的异常分开来考虑。

实际上,每次遍历SomeVariable枚举时都是在重新加载数据。LINQ中的select子句对应于Enumerable.Select:

这个方法是通过延迟执行来实现的。立即返回值是一个对象,它存储执行操作所需的所有信息。此方法表示的查询直到使用foreach枚举对象时才执行[例如]。

这可能不是你想要的行为;您希望SomeVariable热切地填充结果字符串列表。要实现这一点,您可以简单地在枚举对象上调用ToList:

IList<string> SomeVariable = 
(
    from _Something in File.ReadLines(@"file location") 
    select _Something.Split(' ')[1]
).ToList();