我正在实现我自己的可枚举类型。类似这样的东西:
public class LineReaderEnumerable : IEnumerable<string>, IDisposable
{
private readonly LineEnumerator enumerator;
public LineReaderEnumerable(FileStream fileStream)
{
enumerator = new LineEnumerator(new StreamReader(fileStream, Encoding.Default));
}
public IEnumerator<string> GetEnumerator()
{
return enumerator;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Dispose()
{
enumerator.Dispose();
}
}
枚举器类:
public class LineEnumerator : IEnumerator<string>
{
private readonly StreamReader reader;
private string current;
public LineEnumerator(StreamReader reader)
{
this.reader = reader;
}
public void Dispose()
{
reader.Dispose();
}
public bool MoveNext()
{
if (reader.EndOfStream)
{
return false;
}
current = reader.ReadLine();
return true;
}
public void Reset()
{
reader.DiscardBufferedData();
reader.BaseStream.Seek(0, SeekOrigin.Begin);
reader.BaseStream.Position = 0;
}
public string Current
{
get { return current; }
}
object IEnumerator.Current
{
get { return Current; }
}
}
我的问题是:当调用 GetEnumerator() 时,我应该在枚举器上调用 Reset() 还是调用方法(如 foreach)负责执行此操作?
GetEnumerator() 应该创建一个新实例,还是应该始终返回相同的实例?
最佳答案
您的模型已基本损坏 - 您应该创建一个新的 IEnumerator<T>
每次GetEnumerator()
叫做。迭代器应该相互独立。例如,我应该能够写:
var lines = new LinesEnumerable(...);
foreach (var line1 in lines)
{
foreach (var line2 in lines)
{
...
}
}
基本上得到文件中每一行与其他每一行的叉积。
这意味着 LineEnumerable
类不应该被赋予FileStream
- 应该给它一些可以用来获得 FileStream
的东西每次你需要一个,例如一个文件名。
例如,您可以使用迭代器 block 在单个方法调用中完成所有这些操作:
// Like File.ReadLines in .NET 4 - except that's broken (see comments)
public IEnumerable<string> ReadLines(string filename)
{
using (TextReader reader = File.OpenText(filename))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
然后:
var lines = ReadLines(filename);
// foreach loops as before
...那会很好的。
编辑:请注意,某些序列自然只能迭代一次 - 例如网络流,或来自未知种子的随机数序列。
这样的序列确实更好地表示为 IEnumerator<T>
而不是 IEnumerable<T>
,但这使得使用 LINQ 进行过滤等变得更加困难。 IMO 这样的序列应该至少在第二次调用 GetEnumerator()
时抛出异常- 返回同一个迭代器两次是一个非常糟糕的主意。
关于c# - 实现 IEnumerable<T> 和 IEnumerator<T> 时 GetEnumerator() 的推荐行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7673161/