IEnumerator和IEnumerable有什么区别?

127

1
请简要解释一下IEnumerable和IEnumerator。 - Andrew Hare
1
这篇文章可能会对你有所帮助。https://www.c-sharpcorner.com/UploadFile/219d4d/ienumerable-vs-ienumerator-in-C-Sharp/ - Bimal Das
4个回答

134

IEnumerable 是一个定义了一个方法 GetEnumerator 的接口,该方法返回一个 IEnumerator 接口,这样可以对集合进行只读访问。实现了 IEnumerable 接口的集合可以与 foreach 语句一起使用。

定义

IEnumerable 

public IEnumerator GetEnumerator();

IEnumerator

public object Current;
public void Reset();
public bool MoveNext();

1
这篇文章可能会对你有所帮助。https://www.c-sharpcorner.com/UploadFile/219d4d/ienumerable-vs-ienumerator-in-C-Sharp/ - Bimal Das
2
我想补充一点,使用类与foreach语句并不是绝对需要实现IEnumerable。只需要一个匹配的IEnumerator<T> GetEnumerator()方法即可。 - rexcfnghk
1
foreach循环的实际要求甚至不那么严格,也不受这些接口的限制。编译器执行模式匹配。GetEnumerator方法只需要返回一个类/结构体,该类/结构体具有一个Current属性和一个返回布尔值的MoveNext方法。我强烈推荐阅读Eric Lippert关于模式匹配的博客文章 - Bunny83

78

IEnumerator是一个可以枚举的对象:它具有Current属性和MoveNextReset方法(在.NET代码中,您可能不会显式地调用它们,但您可以)。

IEnumerable是一个可枚举的对象...这意味着它具有返回IEnumeratorGetEnumerator方法。

你该使用哪个?唯一使用IEnumerator的原因是如果您有某些东西有非标准的枚举方式(即以逐个返回其各个元素的方式),并且您需要定义如何工作。您将创建实现IEnumerator的新类。但是您仍然需要在IEnumerable类中返回该IEnumerator

要查看枚举器(实现IEnumerator<T>)的样子,请参见任何Enumerator<T>类,例如List<T>Queue<T>Stack<T>中包含的类。要查看实现IEnumerable的类,请参见任何标准集合类。


4
为什么我们需要 IEnumerable 这个抽象接口呢?它只是提供一个访问 Enumerator 的方式,为什么不直接使用 Enumerator 呢? - madmanul
12
@xalz,它们有两种不同的作用。IEnumerable回答问题:我是否能枚举我的元素?IEnumerator回答问题:我如何枚举我的元素?如果你有十个不同的集合都以相同的方式枚举,你不想要分别定义每个集合如何枚举。因此,你可以为这十个集合创建一个共同的实现IEnumerator接口的类,然后每个集合只需要使用该枚举类实现IEnumerable接口即可。这是关注点分离,将保持数据和枚举数据作为单独的操作来处理。 - Ryan Lundy
1
这是唯一一个真正回答了我的问题而不是列出两个类之间差异的答案。IEnumerator是一个枚举集合的类。实现IEnumerable接口的类返回一个IEnumerator。实现IEnumerator接口的类具有自定义的枚举逻辑。 - msteel9999

20
一个枚举器(Enumerator)用来展示列表或集合中的项目。每个枚举器实例都处于某个位置(第1个元素,第7个元素等),并能返回该元素(IEnumerator.Current),或移动至下一个元素(IEnumerator.MoveNext)。在 C# 中编写 foreach 循环时,编译器会生成使用枚举器的代码。
可枚举类(Enumerable)是一种可以提供枚举器(Enumerator)的类。它有一个叫做 GetEnumerator 的方法,可以提供一个查看其项目的枚举器。在 C# 中编写 foreach 循环时,所生成的代码将调用 GetEnumerator 方法以创建循环所使用的枚举器。

1
那篇博客文章相当不准确。 - SLaks

12

IEnumerableIEnumerator 都是接口。 IEnumerable 只有一个叫做 GetEnumerator 的方法。这个方法返回(和所有方法一样返回某个东西,包括 void)另一个类型的接口,这个接口就是 IEnumerator。当您在任何集合类中实现枚举器逻辑时,您实现 IEnumerable(泛型或非泛型)。IEnumerable 只有一个方法,而 IEnumerator 有两个方法(MoveNextReset)和一个属性 Current。为了更容易理解,可以将 IEnumerable 视为包含在其内部的 IEnumerator 箱子(虽然不通过继承或包含)。请参考以下代码以获得更好的理解:

class Test : IEnumerable, IEnumerator
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public object Current
    {
        get { throw new NotImplementedException(); }
    }

    public bool MoveNext()
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接