什么是IEnumerable? IEnumerable及IEnumerable的泛型版本IEnumerableT>是一个接口,它只含有一个方法GetEnumerator。...Enumerable这个静态类型含有很多扩展方法,其扩展的目标是IEnumerableT>。...这个类型实际上的作用就相当于Person[]或List,但我们不能使用它们,因为它们已经实现了IEnumerable,故我们构造一个People类,模拟很多人(People是Person...使用yield关键字实现方法GetEnumerator 如果iterator本身有实现IEnumerator接口(本例就是一个数组),则可以有更容易的方法: public IEnumerator...而且会出现一个问题,就是你无法知道集合的大小(IEnumerable没有Count方法,只有IEnumerableT>才有)。
IEnumerator IEnumerator、IEnumerable接口有相似的名称,这两个接口通常也在一起使用,它们有不同的用途。...IEnumerator接口为类内部的集合提供了迭代方式, IEnumerator 要求你实现三个方法: MoveNext方法:该方法将集合索引加1,并返回一个bool值,指示是否已到达集合的末尾。...Current方法: 返回position位置的当前对象 IEnumerable IEnumerable接口为foreach迭代提供了支持,IEnumerable要求你实现GetEnumerator方法...因此IEnumerable接口的GetEnumerator方法会返回一个IEnumerator接口。要实现IEnumerable,你还必须实现IEnumerator。...为IEnumerator的Current方法提供异常处理。 为什么要这么做?
LINQ查询Object是基于IEnumerableT>对象的,不是集合对象有什么好查的。...其实也就是两点可以扩展,要么提供扩展方法来扩展IEnumerableT>对象,当然你别企图想让VS支持某种关键字让你对应扩展方法。...如果我们是直接使用系统提供的IEnumerableT>对象的话,只需要构建IEnumerableT>对象的扩展方法就能实现对集合类型的扩展。...IQueryableT>继承自IEnumerableT>接口,也就是可以被foreach语法调用的,但是在GetEnumerator方法中才会去执行提供程序的代码。...方法中有两个判断,第一个是判断是否是通过扩展方法方式调用代码的,防止我们直接使用扩展方法,第二个判断是确定我们是否提供了表达式。 那么重点是最后一行代码,它包裹着几层方法调用,到底是啥意思呢?
2、枚举器实现了IEnumerator接口,所以它能做IEnumerator接口定义的所有工作 3、对于有枚举器的类型而言,必须有一个方法来获取它,获取一个对象枚举器的方法是调用对象的GetEnumerator...方法,实现GetEnumerator方法的类型叫做可枚举类型(enumerable),数组是可枚举类型 释义: 所以在此案例中,采用GetEnumerator()方法将获取到的数组的枚举器赋值给定义为枚举器类型的...ie,GetEnumerator()方法获取到的是返回的枚举器的实例 调用方法时MoveNext要在前,Current方法在后。...它们的次序问题我们将通过下个综合实例观察 IEnumerable接口 using System.Runtime.InteropServices; namespace System.Collections...[DispId(-4)] IEnumerator GetEnumerator(); } } 可枚举类是指实现了IEnumerable接口的类,IEnumearable接口只有一个成员
public interface IEnumerableT> : IEnumerable { new IEnumeratorT> GetEnumerator();...2、继承接口IEnumerable: 当我们在类后面加上:IEnumerable后,Visual Studio IDE会冒出来一个小黄灯泡,点进去有提示自动填充接口的约定,我们选第一项实现接口(Visaul...但根据MSDN上面的说法,Reset 方法提供的 COM 互操作性。它不一定需要实现;相反,实施者只需抛出NotSupportedException。...(好像有装箱的行为) 第三,在MoveNext方法内累加索引,并从元素集中读取元素。然后让索引值超出元素集返回个false值。 最后,在Reset方法内让索引值为-1,不过好像直接抛出错误也成。...不过我们也自己实现了一个GetEnumerator(),了解了枚举器的工作原理。本章学习目的达成。
目前我们知道它俩是不一样的东西了,至少从单词层面(ง •_•)ง。那么在 DotNET 中,它们扮演着怎么样的角色呢? 先来看看它们的样子: ? ?...IEnumerable说:我提供了公开枚举器,并且该枚举器支持在非泛型集合上进行简单迭代的功能。 IEnumerator说:我提供了支持对非泛型集合进行简单迭代的功能。...其实看接口的样貌我们就大概能够理解其中的奥秘了,IEnumerable 提供了可以迭代的能力,而这种能力是通过内部的可迭代对象来实现了,这个对象就是IEnumerator。...那么这种具有了可迭代能力的对象有什么好处呢? foreach,没错,它可以享受foreach的语法糖啦。...{ Console.WriteLine(enumeratorLst.Current); } 所以,一层一层的抽丝剥茧,原来脱掉了品如的衣服之后,内部居然是用了IEnumerator的各个属性与方法之间的协作
这么多的获取和修改状态的方法,如果提供出去,还指望使用者能够正常使用,简直是做梦!违背以上两个原则。...T> 了。...IEnumerableT> IEnumerableT> 里面只有两个方法,看起来少多了,那么我们能用吗?...Linq 扩展方法,于是这相当于给此弱引用集合提供了大量可以用来读取状态的方法。...因此,IEnumerableT> 也是不能继承的。 object 看来,我们只能继承自单纯的 object 基类了。此类型没有对托管来说可见的状态,于是谁也不会多次读取状态造成状态不确定了。
List 是一个具体的实现,实现了 IListT> 接口,提供了对动态数组的操作。在大多数情况下,你会更倾向于使用 ListT> 类,因为它提供了一些方便的方法和性能优化,而且可以直接使用。...>{ // 具体实现}虽然这些类没有直接继承自 CollectionT>,但它们提供了一组方法和属性,使得它们可以被当作集合来使用。...泛型的优点有哪些?泛型在编程中具有许多优点,它们提供了一种通用的、类型安全的代码抽象机制。...使用 foreach 遍历访问对象的要求是对象必须实现 IEnumerable 或 IEnumerableT> 接口。这两个接口提供了用于迭代集合的标准方法。...以下是它们之间的一些区别:1、泛型 vs 非泛型HashMap(Dictionary)是泛型的,提供类型安全。
IEnumerator GetEnumerator();} // 泛型版本 : IEnumeratorT>interface IEnumerator{ object Current { get;...但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。...使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。...,此方法通常用于与 COM 的交互操作,许多 .NET 枚举器抛出 NotSupportedException; 集合可以被 foreach, 不一定需要实现 IEnumerable 接口,有 GetEnumerator...一个集合类可以提供多个不同的 GetEnumerator 实现,如 GetEnumerator1,GetEnumerator2,返回不同的 IEnumerator,以实现不同的迭代功能。
集合要支持foreach则需要实现System.Collections.IEnumerable接口[公开枚举数,该枚举数支持在非泛型集合上进行简单迭代, 也可以不实现该接口,该接口定义了一个方法GetEnumerator...(),返回一个支持IEnumerator接口的对象,IEnumerator的成员如下: 名称 说明 bool MoveNex t方法 将枚举数推进到集合的下一个元素 void Rese t方法 将枚举数设置为其初始位置...,也可不实现, 但是必须给提供这两个接口中的同名方法],C#2.0引入了yield return[返回每个元素]和yield break[终止迭代]两个组合而成的上下文关键字。...改写上述代码: //MyEnumerable方法全部删掉 public IEnumerator GetEnumerator() { for (int i = 0; i IEnumerable就可以了[或者说有public IEnumerator GetEnumerator()此方法就可]; 像是匿名方法一样,编译器帮我们做了很多[这里编译器帮我们生成了
} yield break; //当前集合已经遍历完毕,我们就跳出当前函数,其实你不加也可以 //这个作用就是提前结束当前函数,就是说这个函数运行完毕了。...} } 与平常return比较 上面我们看到了yield return 的使用方法,那么这个与return返回集合有什么区别呢?...我们看这个运行结果,这里yield return 和comment return 的输出完全交替了。这里说明是一次调用就返回了一个元素。...其中主要的方法是迭代器方法MoveNext()。...getRandom.count = _count; return _getRandom; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator
一般实现一个集合的方法有:数组,链表,哈希表等等,每种集合因为底层实现不同,遍历集合的方法也不同。...迭代器模式在客户访问类与集合类之间插入一个迭代器,这分离了聚合对象与其遍历行为,对客户也隐藏了其内部细节,且满足“单一职责原则”和“开闭原则”。...其中IEnumerator接口扮演的就是迭代器角色,IEnumberable接口则扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,关于这两个接口的定义可以自行参考MSDN。...此接口至关重要,因为至少必须实现IEnumerableT>的方法,才支持迭代集合。IEnumerable和IEnumerator接口的类图: ?...这样实现的好处在集合类不直接支持IEnumerator接口,而是直接支持另一种接口IEnumerable,其唯一方法是GetEnumerator。此方法用于返回支持 IEnumerator的对象。
其中IEnumerable只有一个返回IEnumerator的GetEnumerator方法。而IEnumerator中有两个方法加一个属性。...接下来开发画瓢,我们继承IEnumerable接口并实现: ? 下面使用原始的方式调用: ? 有朋友开始说了,我们平时都是通过foreache来取值的,没有这样使用过啊。...所以要可以foreach只需要对象定义了GetEnumerator无参方法,并且返回值是IEnumerator或其对应的泛型。细看下图: ? 也就是说,只要可以满足这三步调用即可。...yield的使用 你肯定发现了我们自己去实现IEnumerator接口还是有些许麻烦,并且上面的代码肯定是不够健壮。对的,.net给我们提供了更好的方式。 ?...我们继续来看GetEnumerator的定义和调用: ? 我们调用GetEnumerator的时候,看似里面for循环了一次,其实这个时候没有做任何操作。
接口,所以任何集合类对象都有一个GetEnumerator()方法,该方法可以返回一个实现了 IEnumerator接口的对象,这个返回的IEnumerator对象既不是集合类对象,也不是集合的元素类对象...中表示集合的行为的接口有: 1)ICollection 定义所有集合的大小、枚举数和同步方法。...,该枚举数支持在集合上进行简单迭代 它只有一个方法 GetEnumerator(),该方法可以返回一个IEnumerator接口,通过它可以遍历集合 基本上所有的集合类都实现了这个接口 3)IList...)Queue 实现了接口:ICollection、IEnumerable Queque是队列,先进先出的访问各个元素 可以调用Queque对象的GetEnumerator()方法,得到IEnumerator...对象,来遍历队列中的各个元素 6)Stack 实现了接口:ICollection、IEnumerable Stack是堆栈,后进先出的访问各个元素 可以调用Stack对象的GetEnumerator()
StackT> 当需要使用后进先出顺序(LIFO)的数据结构时,.NET为我们提供了StackT>。StackT> 类提供了Push和Pop方法来实现对StackT>的存取。...QueueT> 当我们需要使用先进先出顺序(FIFO)的数据结构时,.NET 为我们提供了QueueT>。QueueT>类提供了Enqueue和Dequeue方法来实现对QueueT>的存取。...IEnumerableT>的派生类:小结 访问方式 继承自 特点 IEnumerableT> 通过ElementAt 无 所有泛型集合都继承自此接口 有非泛型版本 提供遍历(通过GetEnumerator...) linq的基础,很多linq命令都是他的扩展方法 ICollectionT> 通过ElementAt IEnumerableT> 所有泛型集合都继承自此接口 有非泛型版本 提供Count...IEnumerableT>是整个LINQ的基础。整个LINQ都基于IEnumerableT>的扩展方法之上。C#大部分数据结构都实现了IEnumerableT>。
IQueryable是一个继承了IEnumerable接口的另一个接口。 Queryable是一个静态类型,它集合了许多扩展方法,扩展的目标是IQueryable和IEnumerable。...它令IQueryable和IEnumerable一样,拥有强大的查询能力。 AsQueryable方法将IEnumerableT>转换为IQueryableT>。...因为IQueryableT>继承了IEnumerableT>,所以我们一样要实现GetEnumerator方法。...之后,在主程序的下一行,由于我们调用了ToList方法,此时必须要计算表达式了,故程序开始进行迭代,调用GetEnumerator方法,打印Begin to iterate,然后调用Execute方法,...IQueryableT>继承自IEnumerableT>,所以对于数据遍历来说,它们没有区别。两者都具有延迟执行的效果。
T> srcSequence; IListT> orgSequence; public DemoEnumerable(IEnumerableT> sequence) {...首次调用这个方法时会把输入的序列访问一遍,然后让嵌套类可以在这个列表上反向访问元素。...有时尽管参数实现了 IList 但是它的编译期类型仍然是 IEnumerable,因此我们必须提供新的构造函数的同时修改旧的构造函数。...一、第二次优化 上述代码基本上囊括了大部分情况,但有时我们还会遇到一些集合只实现了 ICollection 而没有实现 IList 的情况,这种情况下我们代码中的 GetEnumerator 方法性能就不是很高了...,但是我们需要在算法的效率和泛型的复用程度之间找到平衡点。
迭代器需引用System.Collections.Generic命名空间 迭代方法1:迭代器创建枚举器 移除C#1.0的枚举器方法PeopleEnum,在继承了IEnumerable接口的People...方法不再需要枚举器了,而是内部的迭代器yield return语句告诉编译器来自动为我们创建枚举器,yield return语句指定了枚举器中下一个可枚举项 C#1我们要写单个类、IEnumerable...接口的实现类(内有GetEnumerator方法)、枚举器类,才能在Main方法实例该类数组遍历它, C#2我们仅写单个类、IEnumerable接口的实现类,不必写枚举器类,便可在Main方法实例该类数组并遍历它了...:如果不实现总类的GetEnumerator方法,Main方法直接采用IEnumerable类型的迭代器(内有GetEnumerator方法),那么就不需要总类的GetEnumerator方法了 using...方法,因为可枚举类型的GetEnumerator方法主体有固定格式,无法再次写个GetEnumerator方法,那样就会重名,且Main方法调用的也不知是哪个正确的GetEnumerator方法 一个类产生多个可枚举类型
先来看一下IEnumerable接口,其实看过这个接口之后,发现它其实是非常的简单,只包含一个方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象,如下面截图所示...image.png 从上面我们知道IEnumerator接口定义了一个Current属性,MoveNext和Reset两个方法,这是多么的简约。既然IEnumerator对象是一个访问器。...其实我定义的两个接口使用的是IMyEnumerable和IMyEnumerator,这里你直接可以去掉My那么就是微软类库里面的接口了,我这里只是自定义罢了,然后我自己定义接口的方法属性,没有严格按照微软的接口进行定义...接口 2、第二个方案是:这个类有一个public的GetEnumerator的实例方法(不用继承IEnumerable实现接口),并且返回类型中有public 的bool MoveNext()实例方法和...实现了IEnmerableT>接口的集合,是强类型的。它为子对象的迭代提供类型更加安全的方式。 自己实现了下,感觉还是懂了一些,虽然还没有彻底的搞明白,但最起码大概知道怎么回事了。