; i < pArray.Length; i++) { _people[i] = pArray[i]; } } public IEnumerator GetEnumerator() { return new PeopleEnum(_people); } } public class PeopleEnum : IEnumerator 经常被问到对IEnumerable和IEnumerator的认识。。。 也一直知道是为了实现迭代、foreach... 那么到底是干什么的呢? IEnumerable里就一个方法,返回IEnumerator类型的对象; public IEnumerator GetEnumerator() IEnumerator里有三个方法需要实现。
IEnumerable包括一个方法GetEnumerator方法,方法返回一个IEnumerator。 IEnumerator是所有非范型迭代器的基础接口。 { Console.WriteLine(person.firstName + person.lastName); } IEnumerator 被遍历的类通过实现IEnumerable接口和实现一个IEnumerator枚举器实现遍历功能。 IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } { return new PeopleEnum(_people); } } public class PeopleEnum:IEnumerator
正文 IEnumerable和IEnumerator,如果不仔细看,是不是都以为它们是同样的一个单词。特别是我们习惯了每天看大量的中文,这种只是很小区别的单词更是容易犯错。 好的,回到今天的主题:IEnumerable和IEnumerator。目前我们知道它俩是不一样的东西了,至少从单词层面(ง •_•)ง。那么在 DotNET 中,它们扮演着怎么样的角色呢? IEnumerator说:我提供了支持对非泛型集合进行简单迭代的功能。 其实看接口的样貌我们就大概能够理解其中的奥秘了,IEnumerable 提供了可以迭代的能力,而这种能力是通过内部的可迭代对象来实现了,这个对象就是IEnumerator。 IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); }
IEnumerator IEnumerator、IEnumerable接口有相似的名称,这两个接口通常也在一起使用,它们有不同的用途。 IEnumerator接口为类内部的集合提供了迭代方式, IEnumerator 要求你实现三个方法: MoveNext方法:该方法将集合索引加1,并返回一个bool值,指示是否已到达集合的末尾。 public IEnumerator GetEnumerator() { return (IEnumerator)this; } 该用哪一个接口? 因此IEnumerable接口的GetEnumerator方法会返回一个IEnumerator接口。要实现IEnumerable,你还必须实现IEnumerator。 最佳实践 在嵌套类中实现IEnumerator,这样你可以创建多个枚举器。 为IEnumerator的Current方法提供异常处理。 为什么要这么做?
1、IEnumerator和IEnumerable的作用 其实IEnumerator和IEnumerable的作用很简单,就是让除数组和集合之外的类型也能支持foreach循环,至于foreach循环, 原因是C#中自定义集合类型要实现foreach的功能,必须通过IEnumerator和IEnumerable两个接口来实现! 2、通过IEnumerator和IEnumerable两个接口实现自定义集合类型的foreach循环功能. 实现了IEnumerable接口之后,发现该接口规定必须返回一个IEnumerator接口(迭代器对象).ok,那么就必须返回一个IEnumerator,那么它是什么呢?别急,下面开始介绍这个接口! 第二步:通过IEnumerable要求实现的GetEnumerator()方法返回一个IEnumerator(迭代器对象),实现该接口必须实现以下三个方法/属性: ?
前言 IEnumerable、IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下。 : image.png 这里的IEnumerator对象,其实就是另外一个接口,这个接口对象有什么呢? 那么让我们看看IEnumerator接口又定义了什么东西。 image.png 从上面我们知道IEnumerator接口定义了一个Current属性,MoveNext和Reset两个方法,这是多么的简约。既然IEnumerator对象是一个访问器。 直接对GetEnumerator()方法进行实现,然后返回IEnumerator即可。
,原理上都是控制IEnumerator MoveNext()的实际,在此我并没有加以实现,一是自己懒惰了些(……),二是Unity本身也未明显提供用以实现这类处理的回调方法,不过有兴趣的朋友倒是可以试试 > innerEnumeratorStack; public CoroutineSimple(Stack<System.Collections.IEnumerator> enumeratorStack) Stack<System.Collections.IEnumerator>顶部的IEnumerator,一旦发现有嵌套的Coroutine产生,那便直接将对应的IEnumerator压栈,可能这么说还是有些许模糊 >> m_enumerators = new List<Stack<System.Collections.IEnumerator>>(); List<Stack<System.Collections.IEnumerator enumerator) { Stack<System.Collections.IEnumerator> newEnumeratorStack = new Stack<System.Collections.IEnumerator
我们先去看看公开的.Net4.0的源程序中IEnumerable<T>、IEnumerable、IEnumerator<T>和IEnumerator这四个接口是如何声明的: 需加微信交流群的,请加小编微信号 public interface IEnumerable<out T> : IEnumerable { new IEnumerator<T> GetEnumerator(); } public interface IEnumerator<out T> : IDisposable, IEnumerator { new T Current { get; } } public interface IEnumerable { IEnumerator GetEnumerator(); 其次,我们要把object Current改成 IEnumerator.Current,这个是实现迭代器的关键。返回元素。
迭代器模式 与 C# IEnumerator/IEnumerable Part1 迭代器模式 与 接口 IEnumerable IEnumerator interface IEnumerable{ IEnumerator GetEnumerator();} // 泛型版本 : IEnumerator<T>interface IEnumerator{ object Current { get; (见下文) Part3 IEnumerator 与 yield 一个集合类想要支持被迭代,最主要的是构造一个 Enumerator 类,实现 IEnumerator 接口,在 GetEnumerator 在实现 IEnumerator 接口时,通常也要实现其泛型版本 IEnumerator{T}。 这段文字看起来有点晕,实际上,实现一个 IEnumerator 也是一个苦力活。 在实际的编程中,一般直接使用已有的集合元素,不必从头实现一个 IEnumerator 。 yield 是 C# 提供语法糖,可以方便的实现 IEnumerator 接口。
实现了IEnumerator接口的类称为枚举器 IEnumerator接口 using System.Runtime.InteropServices; namespace System.Collections [ComVisible(true)] [Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")] public interface IEnumerator 接口,所以它能做IEnumerator接口定义的所有工作 3、对于有枚举器的类型而言,必须有一个方法来获取它,获取一个对象枚举器的方法是调用对象的GetEnumerator方法,实现GetEnumerator // // 返回结果: // 一个可用于循环访问集合的 System.Collections.IEnumerator 对象。 [DispId(-4)] IEnumerator GetEnumerator(); } } 可枚举类是指实现了IEnumerable接口的类,IEnumearable接口只有一个成员
实现 IEnumerator 接口的枚举器包含三个函数成员: Current: 返回当前位置项的属性,只读 MoveNext: 把枚举器位置前进到集合下一项的方法,返回布尔值,位置有效返回 true GetEnumerator() { //... } } 使用 IEnumerator 和 IEnumerable 示例 using System.Collections ; class ColorEnumerator : IEnumerator { private string[] _colors; private int _position = -1 泛型与非泛型版本的主要区别是: IEnumerable 接口的 GetEnumerator 方法要返回实现 IEnumerator 接口的枚举器实例 泛型版本的 Current 属性返回的不是 object 迭代器返回一个泛型的枚举器 yield return 语句声明这是枚举的下一项 public IEnumerator<string> BlackAndWhite() { yield return
System.Collections.IEnumerable接口[公开枚举数,该枚举数支持在非泛型集合上进行简单迭代, 也可以不实现该接口,该接口定义了一个方法GetEnumerator(),返回一个支持IEnumerator 接口的对象,IEnumerator的成员如下: 名称 说明 bool MoveNex t方法 将枚举数推进到集合的下一个元素 void Rese t方法 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前 改写上述代码: //MyEnumerable方法全部删掉 public IEnumerator GetEnumerator() { for (int i = 0; i < items.Length 只需实现一个接口IEnumerable就可以了[或者说有public IEnumerator GetEnumerator()此方法就可]; 像是匿名方法一样,编译器帮我们做了很多[这里编译器帮我们生成了 "实现IEnumerator接口的一个类",通过查看IL代码得知]。
{ private Stack<IEnumerator> executionStack; public EditorCoroutine(IEnumerator = null && result is IEnumerator) { executionStack.Push((IEnumerator > buffer; public static IEnumerator StartEditorCoroutine(IEnumerator iterator) { if = null && result is IEnumerator) { executionStack.Push((IEnumerator > buffer; public static IEnumerator StartEditorCoroutine(IEnumerator iterator) {
lName) { firstName = fName; lastName = lName; } } public class PeopleEnum : IEnumerator Person[] _people; public People(Person[] pArray) { _people = pArray; } public IEnumerator 移除C#1.0的枚举器方法PeopleEnum,在继承了IEnumerable接口的People类中,将GetEnumerator方法中代码改为如下代码,用迭代器创建枚举器 public IEnumerator 便可在Main方法实例该类数组并遍历它了 案例 using System; using System.Collections.Generic; class MyClass { public IEnumerator yield return new AS { caa = 20 }; yield return new AS { caa = 30 }; } public IEnumerator
实现方法GetEnumerator GetEnumerator方法需要一个IEnumerator类型的返回值,这个类型是一个接口,所以我们不能这样写: return new IEnumerator(); 我们可以查看IEnumerator元数据,其解释十分清楚: Enumerator代表一个类似箭头的东西,它指向这个集合当前迭代指向的成员 IEnumerator接口类型对非泛型集合实现迭代 Current 使用yield关键字实现方法GetEnumerator 如果iterator本身有实现IEnumerator接口(本例就是一个数组),则可以有更容易的方法: public IEnumerator yield是一个语法糖,它的本质是为我们实现IEnumerator接口。 迭代显然是非线程安全的,每次IEnumerable都会生成新的IEnumerator,从而形成多个互相不影响的迭代过程。 在迭代时,只能前进不能后退。新的迭代不会记得之前迭代后值的任何变化。
在 C# 中,迭代器模式可以通过实现IEnumerable和IEnumerator接口来实现。 其中 IEnumerable接口定义了一个GetEnumerator方法,返回一个实现了IEnumerator接口的迭代器对象。 IEnumerator接口则定义了访问集合中元素的方法,包括Current、MoveNext和Reset等。 private int[] items = new int[5] { 31, 12, 3, 64, 51 }; // 实现 IEnumerable 接口,返回一个枚举器 public IEnumerator 此外,通过实现IEnumerable和IEnumerator接口,我们可以轻松地在 C# 中实现迭代器模式。 foreach是C#语法糖,用来遍历实现了IEnumerable接口的集合类。
在C#中,迭代器模式可以通过实现IEnumerable接口和IEnumerator接口来实现。 IEnumerable接口定义了一个方法GetEnumerator(),该方法返回一个实现了IEnumerator接口的迭代器对象。 IEnumerator接口包含了MoveNext()方法,用于移动迭代器到集合的下一个元素,以及Current属性,用于获取当前元素的值。 { items[i] = i; } } // 实现IEnumerable接口的方法,返回一个迭代器对象 public IEnumerator GetEnumerator() { return new MyIterator(items); } } // 定义一个迭代器类 class MyIterator : IEnumerator
这个方法必须返回一个实现了IEnumerator 接口的对象。除此以外,我们需要返回的这个对象不仅实现了IEnumerator,而且知道如何枚举ListBox对象。 输出是: Hello World Who Is John Galt 实现 IEnumerator 接口 注意到ListBoxEnumerator不仅需要实现IEnumerator接口,对于ListBox IEnumerable 类和与其相关的 IEnumerator类之间的关系有一点微妙。实现IEnumerator接口的最好办法是在IEnumerable类里创建一个嵌套的IEnumerator类。 为了实现IEnumerator接口,ListBoxEnumerator需要两个方法:MoveNext和Reset,还有一个属性:Current。 注意,返回一个Object是因为IEnumerator接口中Current属性的签名如此。
第二个疑问就是返回类型IEnumerator,名字奇怪也就罢了,我还需要使用yield return这种奇怪的方式来进行返回,而且貌似WaitForSeconds也并不是一个所谓IEnumerator的类型 Coroutine大概是这个样子的…… 随着自己对C#有了进一步的了解,我才慢慢发现,上面所言的那两个奇怪的IEnumerator和yield return,其实并不是Unity的什么独创,相反,他们却是 而至于yield return,其实是C# 2.0新引进的一种实现迭代器模式的简便语法,在之前的C# 1.0中,如果要实现一个完整的迭代器,我们必须要分别实现IEnumerable和IEnumerator 譬如我们写下了如下的代码: IEnumerator Test() { yield return 1; yield return 2; yield return 3; } > m_enumerators = new List<System.Collections.IEnumerator>(); List<System.Collections.IEnumerator> m_enumeratorsBuffer
_employees = employees; } IEnumerator Members#region IEnumerator Members public _employees = employees; } IEnumerator Members#region IEnumerator Members public _employees = employees; } IEnumerator Members#region IEnumerator Members public 其实这是无法避免的,因为for each会把获得的Enumerator转换成对应的接口类型IEnumerator,所以调用的永远是IEnumerator中定义的返回类型为object的Current属性 _employees = employees; } IEnumerator Members#region IEnumerator<Employee> Members