2009-07-06 56 views
22

我正在浏览IEnumerable和IEnumerator,但无法清楚地得到一点。如果我们有foreach,那么为什么我们需要这两个接口?有没有我们必须使用接口的场景。如果是,那么有人可以用一个例子来解释。 欢迎任何建议和评论。 谢谢。IEnumerable,IEnumerator与foreach,何时使用什么

回答

46

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>作为游标。您可以请求一个表给您一个新的游标,并且您可以同时在同一个表上有多个游标。

可能需要一段时间才能真正理解这种差异,但只要记住一个列表(或数组,或其他)没有任何“你在列表中的位置”的概念,而是在列表/ array/whatever does有那么点的状态是有帮助的。

+0

感谢乔恩为你提供的所有帮助。我现在明白了,并且将会学习更多,以便说清楚。 另外我发现下面的链接非常有用: http://stackoverflow.com/questions/558304/can-anyone-explain-ienumerable-and-ienumerator-to-me – Wondering 2009-07-06 07:12:43

+0

这是一个例子,你坚持使用IEnumerator只是保持高效。 http://stackoverflow.com/questions/1018407/what-is-the-most-elegant-way-to-get-a-set-of-items-by-index-from-a-collection/1025137#1025137 – 2009-07-06 11:59:04

+0

@Jon Skeet我真的很喜欢你编码方式Max 的方法。我有一个问题。你使用IEnumberator构造。我知道使用处理它里面的东西()。你为什么在IEnumberator上使用它? – 2012-05-29 05:47:38

8

乔恩说什么。

  • IEnumerableIEnumerable<T>:通过实施此对象指出,它可以给你,你可以用它来遍历在序列/集合的迭代器/集
  • IEnumeratorIEnumerator<T>:如果你调用定义GetEnumerator方法在前一个界面中,您将获得一个迭代器对象作为IEnumerator引用。这使您可以调用MoveNext()并获取当前对象。
  • foreach:从某种意义上说,它是C#构造/外观,因为您不需要知道它如何在引擎盖下工作。它在内部获取迭代器并为您调用正确的方法专注于您想要对每个项目执行的操作(foreach块的内容)。大多数情况下,除非实现自己的类型或自定义迭代,否则只需要foreach,在这种情况下,您需要了解前2个接口。
6

记住,你不来实现IEnumerator及其一些变体使用的foreach - IIRC,它需要一切是返回具有的MoveNext()方法返回一个对象的GetEnumerator()方法一个bool和一个Current属性返回一个对象。您不需要使用IEnumerator和IEnumerable,但通常这是一个非常好的主意。有关更多信息,请参阅here

相关问题