Этот код:
IEnumerable<string> lines = File.ReadLines("file path");
foreach (var line in lines)
{
Console.WriteLine(line);
}
foreach (var line in lines)
{
Console.WriteLine(line);
}
выбрасывает ObjectDisposedException : {"Cannot read from a closed TextReader."}
, если выполняется второй foreach
.
Кажется, что объект-итератор, возвращенный из File.ReadLines(..)
, не может быть перечислит более одного раза. Вы должны получить новый объект итератора, вызвав File.ReadLines(..)
, а затем использовать его для итерации.
Если заменить File.ReadLines(..)
на мою версию (параметры не проверены, это просто пример):
public static IEnumerable<string> MyReadLines(string path)
{
using (var stream = new TextReader(path))
{
string line;
while ((line = stream.ReadLine()) != null)
{
yield return line;
}
}
}
возможно повторять несколько строк строки файла.
Исследование с использованием .Net Reflector
показало, что реализация File.ReadLines(..)
вызывает частный File.InternalReadLines(TextReader reader)
, который создает фактический итератор. Читатель, переданный как параметр, используется в методе MoveNext()
итератора для получения строк файла и расположен, когда мы доходим до конца файла. Это означает, что как только MoveNext()
возвращает false, нет другого способа повторить итерацию второй раз, потому что читатель закрыт, и вы должны получить нового читателя, создав новый итератор с помощью метода ReadLines(..)
. В моей версии новый читатель созданный в методе MoveNext()
каждый раз при запуске новой итерации.
Является ли это ожидаемым поведением метода File.ReadLines(..)
?
Я нахожу тревогу, что нужно каждый раз вызывать метод, прежде чем перечислять результаты. Вам также нужно будет вызывать метод каждый раз, прежде чем вы будете перебирать результаты запроса Linq, который использует этот метод.