Mat*_*olf 11 c# ienumerable ienumerator textreader
我很好奇为什么以下内容在"最后"赋值时抛出错误消息(文本阅读器关闭异常):
IEnumerable<string> textRows = File.ReadLines(sourceTextFileName);
IEnumerator<string> textEnumerator = textRows.GetEnumerator();
string first = textRows.First();
string last = textRows.Last();
Run Code Online (Sandbox Code Playgroud)
但是以下执行正常:
IEnumerable<string> textRows = File.ReadLines(sourceTextFileName);
string first = textRows.First();
string last = textRows.Last();
IEnumerator<string> textEnumerator = textRows.GetEnumerator();
Run Code Online (Sandbox Code Playgroud)
不同行为的原因是什么?
Jon*_*eet 12
据我所知,你在框架中发现了一个错误.由于一些事物的相互作用,这是相当微妙的:
ReadLines(),文件实际上是打开的.就个人而言,我认为这本身就是一个错误; 我希望并希望它是懒惰的 - 只有当你尝试开始迭代它时才打开文件.GetEnumerator()的第一时间上的返回值ReadLines,它实际上将返回相同的参考.First()调用GetEnumerator(),它会创建一个克隆.这将分享相同StreamReader的textEnumeratorFirst()处置它的克隆时,它将处理StreamReader,并将其变量设置为null.这不会影响原始变量,现在指的是已处置的变量StreamReaderLast()调用GetEnumerator(),它会创建一个克隆原始对象的,完整的处置StreamReader.然后它尝试从该读取器读取,并抛出异常.现在将其与第二个版本进行比较:
First()呼叫时GetEnumerator(),返回原始参考,完成打开的阅读器.First()调用时Dispose(),读取器将被处理并且变量设置为nullLast()电话GetEnumerator(),克隆将创建-而是因为它是克隆的价值有一个null参考,一个新的StreamReader创建,所以它能够没有问题读取文件.然后它处理克隆,关闭阅读器GetEnumerator()被调用时,原始对象的第二个克隆,打开另一个StreamReader- 再次,没有问题.所以基本上,第一个片段中的问题是你GetEnumerator()第二次调用(in First())而没有丢弃第一个对象.
这是同一问题的另一个例子:
using System;
using System.IO;
using System.Linq;
class Test
{
static void Main()
{
var lines = File.ReadLines("test.txt");
var query = from x in lines
from y in lines
select x + "/" + y;
foreach (var line in query)
{
Console.WriteLine(line);
}
}
}
Run Code Online (Sandbox Code Playgroud)
你可以通过调用File.ReadLines两次来解决这个问题- 或者使用一个真正懒惰的实现ReadLines,如下所示:
using System.IO;
using System.Linq;
class Test
{
static void Main()
{
var lines = ReadLines("test.txt");
var query = from x in lines
from y in lines
select x + "/" + y;
foreach (var line in query)
{
Console.WriteLine(line);
}
}
static IEnumerable<string> ReadLines(string file)
{
using (var reader = File.OpenText(file))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在后面的代码中,StreamReader每次GetEnumerator()调用都会打开一个new - 因此结果是test.txt中的每对行.
| 归档时间: |
|
| 查看次数: |
242 次 |
| 最近记录: |