枚举器、迭代器、IEnumerable - 有点困惑

Posted

技术标签:

【中文标题】枚举器、迭代器、IEnumerable - 有点困惑【英文标题】:Enumerators, iterators, IEnumerable - a bit confused 【发布时间】:2011-07-31 06:09:48 【问题描述】:

我已通读C# 3.0 in a Nutshell 的迭代器/枚举器部分数次,但我仍然很难掌握它。从他们的名字来看,我最初的想法是 Iterator 会迭代一组 Enumerable 对象。我在正确的轨道上吗?如果是这样,那么常见的泛型集合呢,比如List<T>? List 在其某些操作期间是否创建/使用迭代器? T 是自动可枚举的吗?有演员表吗?一个甚至与另一个有什么关系吗?

在一些相关的说明中,在学习 MVC 时,我看到过这样的代码:

public Article GetArticle(int id)

    return _siteDB.Articles.SingleOrDefault(a => a.ArticleID == id);


public IEnumerable<Article> GetArticle(string title)

    return _siteDB.Articles.Where(a => a.Title.StartsWith(title)).AsEnumerable<Article>();

返回类型为IEnumerable&lt;T&gt; 会给我带来什么?


编辑:好的,我想我开始明白了。我的困惑仍然是迭代器。本书将它们描述为枚举器的生产者。我看不出yield return 实际发生在哪里。每个 yield 都会创建一个新的 Enumerator 吗?

【问题讨论】:

【参考方案1】:

类型 IEnumerable 为您提供 IEnumerable :) 它是一个接口定义方法GetEnumerator(),它返回IEnumerator。您可以根据需要多次调用该方法,并且始终获得 IEnumerator 的新实例。

IEnumerator 具有属性 Current 和方法 MoveNext()Reset() 允许集合枚举。枚举本身可以通过调用 MoveNext() 来完成,如果之前调用 MoveNext() 返回 true,则读取 Current 属性。

文档中有很好的实现和使用示例:http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx

【讨论】:

那么,枚举器会在 IEnumerable 对象上运行吗?枚举器与迭代器有何不同?它们似乎都在做同样的事情——依次遍历对象集合。 没错,枚举器将在 IEnumerable 对象上运行。但在 C# 中,通常使用 foreach 而不是直接使用枚举器。 正如不同答案所说,迭代器只是使用 yield 实现 IEnumerable 或 IEnumerator 接口的方式。 msdn.microsoft.com/en-us/library/dscyy5s0(v=vs.80).aspx 好的,我想我看到了。谢谢!【参考方案2】:

从它们的名字来看,我最初的想法是 Iterator 会迭代一组 Enumerable 对象。我在正确的轨道上吗?如果是这样,那么常见的泛型集合(例如 List)呢? List 在其某些操作期间是否创建/使用迭代器?

iterator 是一种实现返回IEnumerable&lt;T&gt; 的方法的方法——它实际上是一个实现细节。不必创建一些自定义类来枚举集合,您可以使用迭代器来实现它,编译器会为您完成繁重的工作。

返回类型为 IEnumerable 会给我带来什么?

这基本上允许您枚举类型。例如,第二种方法(我个人称之为GetArticles)允许你写:

foreach(var article in GetArticle(theTitle))

   // Do something with article

【讨论】:

【参考方案3】:

让我看看我能不能回答这个问题。

因此,List 实现了 IEnumerable,而不是必须实现它的 T,列表中的任何内容都可以迭代,例如使用 forech 或 for 循环。如果您使用像 List 这样的通用列表,这意味着您拥有的是 T 的列表,其中 T 是您定义的对象类型,这意味着您不必强制转换它,但另一方面您只能放置该列表中相同类型的对象。

上面的代码可能意味着一系列的事情:

1 - 任何实现 IEnumerable 的变量都可以保存 GetArticle 的结果, 例如:

List yourList = GetArticle("test");
Queue myQueue = GetArticle("test");

2 - 查询的实际处理将被延迟。例如,如果您调用 Count,则在您调用该方法之后,这就是它实际执行/解决的时间。

3 - 由于数字 2,如果您按照代码建议在数据库上执行此操作,那么您的连接必须保持打开状态,直到您使用该列表,否则您将收到异常。

我想我已经回答了这些问题。

【讨论】:

以上是关于枚举器、迭代器、IEnumerable - 有点困惑的主要内容,如果未能解决你的问题,请参考以下文章

C#中的枚举器和迭代器

C#迭代器实现

2.3 IQueryable与 IEnumerable的区别

设计模式之迭代器模式

C# IEnumerator IEnumerable接口

迭代器