官方文档例子:
using System; using System.Collections; public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } public class People : IEnumerable { private Person[] _people; public People(Person[] pArray) { _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _people[i] = pArray[i]; } } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator) GetEnumerator(); } public PeopleEnum GetEnumerator() { return new PeopleEnum(_people); } } public class PeopleEnum : IEnumerator { public Person[] _people; // Enumerators are positioned before the first element // until the first MoveNext() call. int position = -1; public PeopleEnum(Person[] list) { _people = list; } public bool MoveNext() { position++; return (position < _people.Length); } public void Reset() { position = -1; } object IEnumerator.Current { get { return Current; } } public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } class App { static void Main() { Person[] peopleArray = new Person[3] { new Person("John", "Smith"), new Person("Jim", "Johnson"), new Person("Sue", "Rabon"), }; People peopleList = new People(peopleArray); foreach (Person p in peopleList) Console.WriteLine(p.firstName + " " + p.lastName); } } /* This code produces output similar to the following: * * John Smith * Jim Johnson * Sue Rabon * */
1、首先看一个简单的列子
1 int[] myArray = { 1, 32, 43, 343 }; 2 //很少这样写的 3 IEnumerator myie = myArray.GetEnumerator(); //获取需要遍历的枚举数 4 myie.Reset(); //重置 5 while (myie.MoveNext()) 6 { 7 int i = (int)myie.Current; //这边涉及一个装箱的操作 8 Console.WriteLine("Value: {0}", i); 9 } 10 //一般情况下是这样写的11 foreach(int item in myArray ) 12 { 13 Console.WriteLine(item.ToString()); 14 }
在大部分的情况下,很多人会使用for和foreach来遍历数组,而对于上面的语法却用的很少,但是对foreach的具体来历还很模糊!
2、先从foreach说起
大家都知道要实现foreach的必须要实现IEnumerable和IEnumerator的接口,只有实现了它们,才能实现遍历,所以要讲foreach的来历,必须要把那两个接口给搞清楚点!
这边也想说明一点的是:如果对这两个接口有了一定的了解后,只要实现那个GetEnumerator方法即可,而不需要实现于IEnumerable接口,这只是针对对这两个接口有一定了解的朋友!
3、IEnumerable
具体的作用:就是使实现这个接口的对象成为可枚举类型。
IEnumerable接口包含一个GetEnumerator方法,返回值为IEnumerator的类型!
代码如下:
1 public class MyColors : IEnumerable 2 { 3 string[] colors = { "Red", "Yellow", "Biue" }; 4 5 public IEnumerator GetEnumerator() 6 { 7 8 return colors.GetEnumerator(); 9 10 } 11 }
那么我们在客户端进行调用的时候就可以这样做了!
1 MyColors colors = new MyColors(); 2 foreach (string item in colors) 3 { 4 Console.WriteLine(item); 5 }
这 样就能 使用实现这个接口的对象进行foreach遍历了,就是这么简单的一个列子,这边可能有的人会有疑问,我们就实现了IEnumerable接口但却没实现 IEnumerator接口,可是我们不是说只有实现了这两个接口才可以进行foreach遍历吗?可以这样说当使用forach进行遍历的时候,编译器 会到这个对象的类中去寻找GetEnumerator方法,找到这个方法后返回这个一个IEnumerator的对象(枚举数),而我这边返回的是 “colors.GetEnumerator()”,是一个数组对象调用它本身中的“GetEnumerator”方法,所以说数组本身就实现了 IEnumerator接口,那么两个接口都实现了,不就好实现foreach遍历了,其实在实现遍历枚举数的时候编译器会自动去调用数组中实现枚举数的 类中的方法(这将在下一篇中讲到)!
4、IEnumerator
接口的作用:实现可枚举数
首先看一下接口的定义:
包含一个属性两个方法
MoveNext → 把当前的项移动到下一项(类似于索引值),返回一个bool值,这个bool值用来检查当前项是否超出了枚举数的范围!
Current → 获取当前项的值,返回一个object的类型(这边会涉及到装箱和拆箱的问题 → 后面讲泛型的时候会涉及到)!
Reset → 顾名思义也就是把一些值恢复为默认值,比如把当前项恢复到默认状态值!
代码如下:
1 public class MyIEnumerator : IEnumerator 2 { 3 4 string[] colors; //定义一个数组,用来存储数据 5 int position = -1; //定义当前项的默认值,也就是索引值,一开始认识数组的索引从“0”开始,怎么默认设置他为“-1”呢,最后才想明白,这样设置是合情合理的! 6 7 public MyIEnumerator(string[] colors) 8 { 9 this.colors = new string[colors.Length]; 10 11 for (int i = 0; i < this.colors.Length; i++) 12 { 13 this.colors[i] = colors[i]; 14 } 15 } 16 17 public object Current //根据当前项获取相应的值18 { 19 get 20 { 21 return colors[position]; //返回当前项的值,但是会做一个装箱的操作!22 } 23 } 24 25 public bool MoveNext() //移动到下一项26 { 27 if (position < colors.Length - 1) //这就是设置默认值为-1的根据28 { 29 position++; 30 return true; 31 } 32 else 33 { 34 return false; 35 } 36 } 37 38 public void Reset() //重置当前项的值,恢复为默认值39 { 40 this.position = -1; 41 } 42 }
在 第三点讲到的 IEnumerable接口中GetEnumerator方法是获取要遍历的枚举数,在我们没有创建自己的遍历枚举数的类时,我们使用的是Array的遍 历枚举数的方法(关于数组的可枚举类型和枚举数会在下一篇讲到),但这个有的时候不一定适合我们,我们需要为自己定制一个更合适的,所以我们要创建自己的 枚举数类(也就是上面的代码),把第三点和第四点的代码合并起来(改动一点代码),如下:
1 public class MyColors //: IEnumerable 2 { 3 string[] colors = { "Red", "Yellow", "Biue" }; 4 5 public IEnumerator GetEnumerator() 6 { 7 return new MyIEnumerator(colors); 8 9 //这边就是我们要改动的地方,返回一个自己创建的类型,不是在返回数组的IEnumerator对象了,而是我们自己创建的枚举数对象→MyIEnumerator10 } 11 }
客户端是不要改动代码的,然后只要使用foreach直接遍历就可以了!
5、关于可枚举类型和枚举数
①可枚举类型 → 实现IEnumerable接口,可以不需要直接实现这个接口,但必须有个GetEnumerator方法,返回值类型必须为IEnumerator类型,也就是第四点最后一段代码中接口注释的那种写法!
②枚举数 → 实现IEnumerator接口,实现全部方法,首先是调用GetEnumerator返回一个类型为IEnumerator的枚举数,然后编译器会隐式的调用实现IEnumerator类中的方法和属性!
总结:所以实现foreach遍历,必须达到上面的两种条件才能进行遍历对象,他们可以写在一起也可以分开,最好是分开,进行职责分离,一个类干一件事总归是好事!
来源:http://www.cnblogs.com/yangcaogui/archive/2011/12/04/2266589.html
/// <summary> /// 处理数据源,转换成IEnumerator,方便进行下一步操作 /// </summary> /// <param name="source">数据源,先统一装箱</param> /// <returns>数据源的IEnumerable形式</returns> private IEnumerator getResolvedDataSource(object source) { if (source is IEnumerator) return (IEnumerator)source; else if (source is IList) return ((IList)source).GetEnumerator(); else if (source is DataSet) return (((DataSet)source).Tables[0].DefaultView.GetEnumerator()); else if (source is DataTable) return ((DataTable)source).DefaultView.GetEnumerator(); else return null; }
相关推荐
Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大...
C#自建集合类MyArrayList实现集合接口IEnumerable, IEnumerator, 实现方法 inr add(object value),void Remove(object o), int Count, void Clear()
实现IComparable和IComparer接口,IEnumerable和IEnumerator接口,IDisposable接口的例子。
(1)编写IEnglishDimensions和IMetricDimensions两个接口,同时以公制单位和英制单位显示框的尺寸。Box类继承IEnglishDimensions和...使用集合接口IEnumerable和Ienumerator实现装入水果过程及遍历水果。
我们经常使用的大多数集合实际上都已经实现了枚举的接口IEnumerable和IEnumerator接口,这样才能使用foreach迭代,有些是含有某种抽象了枚举细节的接口:ArrayList类型有索引,BitArray有Get方法,哈希表和字典有键...
在本文中我们将讲解使用IDisposable释放托管内存和非托管内存。 A.首先需要让类实现IDisposable接口,然后实现IDispose方法。 A.a核心Disponse(bool isDisponse) 1.此方法首先判断isReadyDisposed(判断是否第...
一、实现foreach的关键: 必须为包含有GetEnumerator()...四、如果返回类型为IEnumerator编译时会实现一个实现了IEnumerator接口的类 五、同理如果返回类型为IEnumerable编译时会实现一个实现了IEnumerable接口的类
本文实例讲述了php和C#的yield迭代器实现方法对比。...IEnumerable表示一个类可以迭代,也就是可以用foreach遍历,IEnumerator是真正的迭代器实现,IEnumerable和IEnumerator一个是使用迭代器的接口,一个是实现迭
C#中的迭代器封装在IEnumerable和IEnumerator和他们的泛型接口中。 IEnumerable:定义了一个可以获取IEnumerator的方法—GetEnumerator()。 //IEnumerable的代码实现 public interface IEnumerable { ...
前言 在foreach语句中使用枚举,可以迭代数组或集合中的元素,且无须知道集合中的元素的个数。如图显示了调用foreach方法的客户端和集合之间的...有一个名为GetEnumerator()的方法它返回实现了IEnumerator接口的对象就
一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代器方法来实现foreach的遍历,且自定义...
1、类要实现公共方法 public IEnumerator GetEnumerator(){},还可以继承IEnumerable接口来实现这个方法 2、类实现了 public IEnumerator GetEnumerator(){}中,要返回一个对象用于遍历的,当然这个对象必须...
◦类库:Yomigana 类库容许对串(string)类型加注 Yomigana,同时也支持对一般类型的注解功能,任何实现了IEnumerable接口的对象都可以被串类型和泛型的实例注解。为了简化复杂的注解字符串比较特设计了支持各种...
5.1 IEnumerable 、IEnumerator 10 5.1.1 正常使用 10 5.1.2 C#的 yield 12 5.2 IEnumerable <T> 12 5.3 IEnumerator <T> 12 5.4 ICollection 12 5.5 ICollection <T> 13 5.6 IList 13 5.7 IList <T> 13 ...
22.1 使用驱动器、目录和文件739 22.1.1 DriveInfo类739 22.1.2 Directory和 DirectoryInfo类743 22.1.3 File和FileInfo类749 22.1.4 使用路径753 22.1.5 文件和目录的属性、 特性和访问控制列表757 22.2 读写...
10.2.2 IEnumerable和IEnumerator 284 10.2.3 ICollection 285 10.2.4 Lists和IList 286 10.2.5 字典和IDictionary 287 10.2.6 散列表 288 10.2.7 SortedList 292 10.2.8 Queue和Stack 292 10.3 专用集合 295...
实现一些标准的.NET接口(IEnumerable,IComparable,IComparer,IEquatable,IEnumerator等) 延迟初始化。 泛型(在委托,事件和方法中)。 代表们 事件及其用法:标准和自定义。 异常并以有意义的方式处理它们。...
} } #endregion IEnumerable 成员#region IEnumerable 成员 public IEnumerator GetEnumerator() { return list.GetEnumerator(); } #endregion}Item是自定义的一个类。没什么具体的意义。 这样偷一下,上面的这个...