【发布时间】:2009-07-06 06:13:59
【问题描述】:
我正在通过 IEnumerable 和 IEnumerator ,但无法清楚地得到一点..如果我们有foreach,那么为什么我们需要这两个接口?有没有我们必须使用接口的场景。如果是,那么有人可以举个例子来解释一下。 欢迎任何建议和评论。 谢谢。
【问题讨论】:
标签: c# enumeration
我正在通过 IEnumerable 和 IEnumerator ,但无法清楚地得到一点..如果我们有foreach,那么为什么我们需要这两个接口?有没有我们必须使用接口的场景。如果是,那么有人可以举个例子来解释一下。 欢迎任何建议和评论。 谢谢。
【问题讨论】:
标签: c# enumeration
foreach使用接口在很多情况下。如果你想实现一个foreach 可以使用的序列,你需要这些接口。 (虽然迭代器块通常使这个实现任务非常简单。)
但是,偶尔直接使用迭代器会很有用。一个很好的例子是尝试“配对”两个不同的序列。例如,假设您收到两个序列 - 一个是姓名,一个是年龄,并且您希望将这两个序列一起打印。你可以写:
static void PrintNamesAndAges(IEnumerable<string> names, IEnumerable<int> ages)
{
using (IEnumerator<int> ageIterator = ages.GetEnumerator())
{
foreach (string name in names)
{
if (!ageIterator.MoveNext())
{
throw new ArgumentException("Not enough ages");
}
Console.WriteLine("{0} is {1} years old", name, ageIterator.Current);
}
if (ageIterator.MoveNext())
{
throw new ArgumentException("Not enough names");
}
}
}
同样,如果您想以与其他项目不同的方式处理(例如)第一项,则使用迭代器会很有用:
public T Max<T>(IEnumerable<T> items)
{
Comparer<T> comparer = Comparer<T>.Default;
using (IEnumerator<T> iterator = items.GetEnumerator())
{
if (!iterator.MoveNext())
{
throw new InvalidOperationException("No elements");
}
T currentMax = iterator.Current;
// Now we've got an initial value, loop over the rest
while (iterator.MoveNext())
{
T candidate = iterator.Current;
if (comparer.Compare(candidate, currentMax) > 0)
{
currentMax = candidate;
}
}
return currentMax;
}
}
现在,如果您对IEnumerator<T> 和IEnumerable<T> 之间的区别感兴趣,您可能想用数据库术语来考虑它:将IEnumerable<T> 视为一个表,将IEnumerator<T> 视为一个游标。你可以要求一个表给你一个新的游标,你可以在同一个表上同时有多个游标。
真正理解这种差异可能需要一段时间,但只要记住列表(或数组,或其他)没有任何“您在列表中的位置”的概念,而是对该列表/数组的迭代器/whatever does 有这种状态是有帮助的。
【讨论】:
IEnumerator<T> 实现了IDisposable,所以当你完成它时你应该调用Dispose。特别是,如果您使用的序列是从迭代器块生成的,则允许执行 finally 块 - 因此可以从那里释放资源。
乔恩说了什么。
IEnumerable 或 IEnumerable<T> :通过实现这个,一个对象声明它可以给你一个迭代器,你可以用它来遍历序列/集合/集合IEnumerator 或 IEnumerator<T> :如果调用之前接口中定义的 GetEnumerator 方法,则会得到一个迭代器对象作为 IEnumerator 引用。这使您可以调用 MoveNext() 并获取 Current 对象。foreach :在某种意义上是一个 C# 构造/外观,因为您不需要知道它在幕后是如何工作的。它在内部获取迭代器并调用正确的方法让您专注于您想要对每个项目(foreach 块的内容)执行的操作。大多数情况下,您只需要 foreach ,除非您要实现自己的类型或自定义迭代,在这种情况下,您需要了解前 2 个接口。【讨论】:
请记住,您没有必须实现 IEnumerator 及其变体来使用 foreach - IIRC,它所需要的只是一个 GetEnumerator() 方法,该方法返回一个具有 MoveNext() 的对象方法返回一个布尔值,一个 Current 属性返回一个对象。您不需要使用 IEnumerator 和 IEnumerable,尽管这样做通常是一个非常好的主意。请参阅here 了解更多信息。
【讨论】: