C#c ienumerable t和IEnumerator的区别,如何实现

C#IEnumerable和IEnumerator的区别,如何实现_百度知道  一直以来,搞不懂IEnumerable与IEnumerator这两个接口的区别,今天看了一下MSDN并在网上搜了一把关于他们的区别,似乎理解了,但还是弄不懂他们最主要的区别是什么。看看MSDN是怎么定义他们的吧。
&1public&interface&IEnumerable&2{&3&&&&IEnumerator&GetEnumerator();&4}&5&&6public&interface&IEnumerator&7{&8&&&&bool&MoveNext();&9&&&&void&Reset();<span style="color: #&<span style="color: #&&&&Object&Current&{&get;&}<span style="color: #}
  再贴一个MSDN给出的例子:
Code&1using&S&2using&System.C&3public&class&Person&4{&5&&&&public&Person(string&fName,&string&lName)&6&&&&{&7&&&&&&&&this.firstName&=&fN&8&&&&&&&&this.lastName&=&lN&9&&&&}<span style="color: #&&&&public&string&firstN<span style="color: #&&&&public&string&lastN<span style="color: #}<span style="color: #public&class&People&:&IEnumerable<span style="color: #{<span style="color: #&&&&private&Person[]&_<span style="color: #&&&&public&People(Person[]&pArray)<span style="color: #&&&&{<span style="color: #&&&&&&&&_people&=&new&Person[pArray.Length];<span style="color: #&&&&&&&&for&(int&i&=&<span style="color: #;&i&&&pArray.L&i++)<span style="color: #&&&&&&&&{<span style="color: #&&&&&&&&&&&&_people[i]&=&pArray[i];<span style="color: #&&&&&&&&}<span style="color: #&&&&}<span style="color: #&&&&public&IEnumerator&GetEnumerator()<span style="color: #&&&&{<span style="color: #&&&&&&&&return&new&PeopleEnum(_people);<span style="color: #&&&&}<span style="color: #}<span style="color: #public&class&PeopleEnum&:&IEnumerator<span style="color: #{<span style="color: #&&&&public&Person[]&_<span style="color: #&&&&//&Enumerators&are&positioned&before&the&first&element&<span style="color: #&&&&//&until&the&first&MoveNext()&call.&<span style="color: #&&&&int&position&=&-<span style="color: #;<span style="color: #&&&&public&PeopleEnum(Person[]&list)<span style="color: #&&&&{<span style="color: #&&&&&&&&_people&=&<span style="color: #&&&&}<span style="color: #&&&&public&bool&MoveNext()<span style="color: #&&&&{<span style="color: #&&&&&&&&position++;<span style="color: #&&&&&&&&return&(position&&&_people.Length);<span style="color: #&&&&}<span style="color: #&&&&public&void&Reset()<span style="color: #&&&&{<span style="color: #&&&&&&&&position&=&-<span style="color: #;<span style="color: #&&&&}<span style="color: #&&&&public&object&Current<span style="color: #&&&&{<span style="color: #&&&&&&&&get<span style="color: #&&&&&&&&{<span style="color: #&&&&&&&&&&&&try<span style="color: #&&&&&&&&&&&&{<span style="color: #&&&&&&&&&&&&&&&&return&_people[position];<span style="color: #&&&&&&&&&&&&}<span style="color: #&&&&&&&&&&&&catch&(IndexOutOfRangeException)<span style="color: #&&&&&&&&&&&&{<span style="color: #&&&&&&&&&&&&&&&&throw&new&InvalidOperationException();<span style="color: #&&&&&&&&&&&&}<span style="color: #&&&&&&&&}<span style="color: #&&&&}<span style="color: #}<span style="color: #class&App<span style="color: #{<span style="color: #&&&&static&void&Main()<span style="color: #&&&&{<span style="color: #&&&&&&&&Person[]&peopleArray&=&new&Person[<span style="color: #]<span style="color: #&&&&&&&&{<span style="color: #&&&&&&&&&&&&new&Person("John",&"Smith"),<span style="color: #&&&&&&&&&&&&new&Person("Jim",&"Johnson"),<span style="color: #&&&&&&&&&&&&new&Person("Sue",&"Rabon"),<span style="color: #&&&&&&&&};<span style="color: #&&&&&&&&People&peopleList&=&new&People(peopleArray);<span style="color: #&&&&&&&&foreach&(Person&p&in&peopleList)<span style="color: #&&&&&&&&&&&&Console.WriteLine(p.firstName&+&"&"&+&p.lastName);<span style="color: #&&&&}<span style="color: #}<span style="color: #/**//*&This&code&produces&output&similar&to&the&following:<span style="color: #&*&<span style="color: #&*&John&Smith<span style="color: #&*&Jim&Johnson<span style="color: #&*&Sue&Rabon<span style="color: #&*&<span style="color: #&*/
  最后看一段别人的总结,水平高的人应该理解更深吧。我先贴出来供以后参考。  
  1、一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方式返回IEnumerator object)。&  2、IEnumerator object具体实现了iterator(通过MoveNext(),Reset(),Current)。&  3、从这两个接口的用词选择上,也可以看出其不同:IEnumerable是一个声明式的接口,声明实现该接口的class是&#8220;可枚举(enumerable)&#8221;的,但并没有说明如何实现枚举器(iterator);IEnumerator是一个实现式的接口,IEnumerator object就是一个iterator。&  4、IEnumerable和IEnumerator通过IEnumerable的GetEnumerator()方法建立了连接,client可以通过IEnumerable的GetEnumerator()得到IEnumerator object,在这个意义上,将GetEnumerator()看作IEnumerator object的factory method也未尝不可。  IEnumerator&& 是所有枚举数的基接口。
  枚举数只允许读取集合中的数据。枚举数无法用于修改基础集合。&&&&&&   最初,枚举数被定位于集合中第一个元素的前面。Reset&& 也将枚举数返回到此位置。在此位置,调用&& Current&& 会引发异常。因此,在读取&& Current&& 的值之前,必须调用&& MoveNext&& 将枚举数提前到集合的第一个元素。&& &&& & 在调用&& MoveNext&& 或&& Reset&& 之前,Current&& 返回同一对象。MoveNext&& 将&& Current&& 设置为下一个元素。&&&&&&   在传递到集合的末尾之后,枚举数放在集合中最后一个元素后面,且调用&& MoveNext&& 会返回&& false。如果最后一次调用&& MoveNext&& 返回&& false,则调用&& Current&& 会引发异常。若要再次将&& Current&& 设置为集合的第一个元素,可以调用&& Reset,然后再调用&& MoveNext。&&&&&&   只要集合保持不变,枚举数就将保持有效。如果对集合进行了更改(例如添加、修改或删除元素),则该枚举数将失效且不可恢复,并且下一次对&& MoveNext&& 或&& Reset&& 的调用将引发&& InvalidOperationException。如果在&& MoveNext&& 和&& Current&& 之间修改集合,那么即使枚举数已经无效,Current&& 也将返回它所设置成的元素。&&&&&&   枚举数没有对集合的独占访问权;因此,枚举一个集合在本质上不是一个线程安全的过程。甚至在对集合进行同步处理时,其他线程仍可以修改该集合,这会导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。
  参考资料&
阅读(...) 评论()Programme language(60)
转自:/shaosks/archive//2193270.html
解释了IEnumerable 与 IEnumerator的区别,并使用给出相关实例。
转自:http://blog.csdn.net/byondocean/article/details/6871881
从使用foreach出发一步步解释IEnumerable的使用。
转自:/junbird-nest/archive//2439828.html
C# IEnumerable&T&、IEnumerator&T&、List&T&、ArrayList、[]数组各各的区别
http://blog.csdn.net/fssssssss/article/details/7536989
使用实例解释了IEnumerable&T&的使用。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:460971次
积分:5885
积分:5885
排名:第3082名
原创:82篇
转载:335篇
评论:55条
(1)(3)(12)(3)(4)(1)(9)(7)(11)(10)(2)(1)(2)(5)(10)(8)(11)(2)(3)(6)(6)(3)(16)(6)(1)(14)(14)(11)(1)(7)(7)(6)(5)(5)(7)(17)(7)(6)(32)(24)(10)(20)(22)(13)(2)(1)(2)(2)(5)(3)(1)(13)(4)(3)(2)(12)(11)C#基础知识系列九(对IEnumerable和IEnumerator接口的糊涂认识)
&  IEnumerable、IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下。以备自己日后可以来翻查,同时也希望园子里的大牛们,来帮我看看理解的怎么样。
查看并使用两个接口
  接下来我们先来看看两个接口的定义。
  先来看一下IEnumerable接口,其实看过这个接口之后,发现它其实是非常的简单,只包含一个方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象,如下面截图所示:
这里的IEnumerator对象,其实就是另外一个接口,这个接口对象有什么呢?它是一个真正的集合访问器,没有它,就不能使用foreach语句遍历集合或数组,因为只有IEnumerator对象才能访问集合中的项,假如连集合中的项都访问不了,那么进行集合的循环遍历是不可能的事情了。那么让我们看看IEnumerator接口又定义了什么东西。
从上面我们知道IEnumerator接口定义了一个Current属性,MoveNext和Reset两个方法,这是多么的简约。既然IEnumerator对象是一个访问器。那至少应该有一个Current属性,来获取当前集合中的项吧。MoveNext方法只是将游标的内部位置向前移动(就是移到一下个元素而已),要想进行循环遍历,不向前移动一下怎么行呢?
通过注释也可以明确的发现他们的用处。
下面我们来看一个简单的例子:
& & & & static void Main(string[] args)
& & & & & & int[] iArr = { 1, 3, 4, 6, 7, 9 };
& & & & & & foreach (int i in iArr)
& & & & & & {
& & & & & & & & Console.WriteLine(i.ToString());
& & & & & & }
& & & & & & Console.ReadLine();
F5来运行代码
结果有了,说明简单的数组是可以支持foreach循环的。
下面我们来自己来做一个小例子,先来定义实体类
& & /// &summary&
& & /// 个人的实体类
& & /// &/summary&
& & public class Person
& & & & public string Name { }
& & & & public int Age { }
& & /// &summary&
& & /// 一群人的实体类
& & /// &/summary&
& & public class People
& & { & & & & & &
& & & & Person[] personList = new Person[4];
& & & & public People()
& & & & & & personList[0] = new Person() { Name = &aehyok&, Age = 25 };
& & & & & & personList[1] = new Person() { Name = &Kris&, Age = 22 };
& & & & & & personList[2] = new Person() { Name = &Leo&, Age = 21 };
& & & & & & personList[3] = new Person() { Name = &Niki&, Age = 23 };
如上面代码所示,一个Person类是个人的实体类,然后People类是一群人的实体类,按照和上面数组类似的格式,下面我们进行调用
& & & & static void Main(string[] args)
       ///直接对一群人实例对象进行foreach
& & & & & & People people = new People();
& & & & & & foreach (Person p in people)
& & & & & & {
& & & & & & & & Console.WriteLine(&Name:{0}\tAge{1}&,p.Name,p.Age);
& & & & & & }
& & & & & & Console.ReadLine();
还没来得及编译,错误就来了
所以我们根据上面的讲解我们就让People类实现IEnumerable接口吧。现在先来修改People实体类。
& & /// &summary&
& & /// 个人的实体类
& & /// &/summary&
& & public class Person
& & & & public string Name { }
& & & & public int Age { }
& & /// &summary&
& & /// 一群人的实体类
& & /// &/summary&
& & public class People:IEnumerable
& & { & & & & & &
& & & & Person[] personList = new Person[4];
& & & & public People()
& & & & & & personList[0] = new Person() { Name = &aehyok&, Age = 25 };
& & & & & & personList[1] = new Person() { Name = &Kris&, Age = 22 };
& & & & & & personList[2] = new Person() { Name = &Leo&, Age = 21 };
& & & & & & personList[3] = new Person() { Name = &Niki&, Age = 23 };
& & & & public IEnumerator GetEnumerator()
& & & & & & return this.personList.GetEnumerator();
继承实现接口,完成该方法之后,就可以在调用时用foreach了。
注意:其实这里完全不用继承该接口。直接对GetEnumerator()方法进行实现,然后返回IEnumerator即可。
这样还可以有另外一种调用方式
& & & & static void Main(string[] args)
& & & & & & People people = new People();
& & & & & & foreach (Person p in people)
& & & & & & {
& & & & & & & & Console.WriteLine(&Name:{0}\tAge{1}&,p.Name,p.Age);
& & & & & & }
& & & & & & Console.WriteLine(&&);
& & & & & & ///直接获取迭代器
& & & & & & IEnumerator i = people.GetEnumerator();
& & & & & & while (i.MoveNext())
& & & & & & {
& & & & & & & & Person person = (Person)i.C
& & & & & & & & Console.WriteLine(&Name:{0}\tAge{1}&, person.Name, person.Age);
& & & & & & }
& & & & & & Console.ReadLine();
自定义两个接口并进行实现
  上面我们是通过继承微软类库中的接口来实现的实体集合的foreach遍历。下面我们来演示一下完全通过自己创建接口来实现自己定义的实例集合的foreach遍历。首先我们来实现一个简单的迭代器。
第一步:定义一个接口IMyEnumerator,之后所有迭代器都要进行实现
& & /// &summary&
& & /// 要求所有的迭代器全部实现该接口
& & /// &/summary&
& & interface IMyEnumerator
& & & & bool MoveNext();
& & & & object Current{};
第二步:再定义一个接口IMyEnumerable,所有集合要实现该接口
& & /// &summary&
& & /// 要求所有的集合实现该接口
& & /// 这样一来,客户端就可以针对该接口编码
& & /// 而无须关注具体的实现
& & /// &/summary&
& & interface IMyEnumerable
& & & & IMyEnumerator GetEnumerator();
& & & & int Count{};
第三步:一个简单的集合类MyList,实现IMyEnumerable。
& & class MyList:IMyEnumerable
& & & & int[] items = {0,1,2,3,4,5,6,7,8,9};
& & & & IMyEnumerator myE
& & & & public int this[int i]
& & & & & & get { return items[i]; }
& & & & & & set { this.items[i] = }
& & & & public int Count
& & & & & & get { return items.L }
& & & & public IMyEnumerator GetEnumerator()
& & & & & & if (myEnumerator == null)
& & & & & & {
& & & & & & & & myEnumerator = new MyEnumerator(this);
& & & & & & }
& & & & & & return myE
第四步:其实集合中也需要进行使用实现了第一步的迭代器,所以在此就是要实现这个迭代器
public class MyEnumerator:IMyEnumerator
& & & & int index = 0;
& & & & MyList myL
& & & & public MyEnumerator(MyList myList)
& & & & & & this.myList = myL
& & & & public bool MoveNext()
& & & & & & if (index + 1 & =myList.Count)
& & & & & & {
& & & & & & & & index = 1;
& & & & & & & &
& & & & & & }
& & & & & & else
& & & & & & {
& & & & & & & & index++;
& & & & & & & &
& & & & & & }
& & & & public object Current
& & & & & & get { return myList[index]; }
第五步:简单调用进行调试
& & & & static void Main(string[] args)
& & & & & & ///使用接口IMyEnumerable代替MyList
& & & & & & IMyEnumerable list = new MyList();
& & & & & & ///得到迭代器,在循环中针对迭代器进行编码,而不是集合MyList
& & & & & & IMyEnumerator enumerator = list.GetEnumerator();
& & & & & & for (int i = 0; i & list.C i++)
& & & & & & {
& & & & & & & & object current = enumerator.C
& & & & & & & & Console.WriteLine(current.ToString());
& & & & & & & & enumerator.MoveNext();
& & & & & & & &&
& & & & & & }
& & & & & & Console.WriteLine(&&);
& & & & & & ///重新创建一个新的对象
& & & & & & IMyEnumerable list1 = new MyList();
& & & & & & IMyEnumerator enumerator1 = list1.GetEnumerator();
& & & & & & while (enumerator1.MoveNext()) & &//因为此处闲下移了一位,所以从1开始
& & & & & & {
& & & & & & & & object current = enumerator1.C
& & & & & & & & Console.WriteLine(current.ToString());
& & & & & & }
& & & & & & Console.ReadLine();
&  其实我定义的两个接口使用的是IMyEnumerable和IMyEnumerator,这里你直接可以去掉My那么就是微软类库里面的接口了,我这里只是自定义罢了,然后我自己定义接口的方法属性,没有严格按照微软的接口进行定义,但是差不多,只需要进行简单的修正就可以进行调用。这里有一个版本的。
&View Code
其实上面例子中的调用我们就可以使用foreach来调用了,那么现在我们来用foreach来调用看看。
& & & & static void Main(string[] args)
& & & & & & MyList list=new MyList();
& & & & & & foreach (object obj in list)
& & & & & & {
& & & & & & & & Console.WriteLine(obj.ToString());
& & & & & & }
& & & & & & Console.ReadLine();
通过上面我实现的几个简单的例子可以发现,一个类型支持foreach遍历的条件可以是:
  1、第一个方案是:这个类实现IEnumerable接口
  2、第二个方案是:这个类有一个public的GetEnumerator的实例方法(不用继承IEnumerable实现接口),并且返回类型中有public 的bool MoveNext()实例方法和public的Current实例属性。
实现了IEnmerable&T&接口的集合,是强类型的。它为子对象的迭代提供类型更加安全的方式。
自己实现了下,感觉还是懂了一些,虽然还没有彻底的搞明白,但最起码大概知道怎么回事了。有空再来看看yield关键字的用法。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'文章数:192
访问量:9271
注册日期:
阅读量:5863
阅读量:12276
阅读量:346405
阅读量:1046314
51CTO推荐博文
通过一个例子来看-------------------------------------------------------Student.csusing&S
using&System.Collections.G
using&System.L
using&System.T
using&System.Threading.T
using&System.C
namespace&ConsoleApplication6
&&&&public&class&Student:IEnumerable
&&&&&&&&//数组
&&&&&&&&public&string[]&s;
&&&&&&&&//索引器
&&&&&&&&public&int&i;
&&&&&&&&public&Student(string[]&str)//构造函数,初始化数组
&&&&&&&&&&&&s&=&
&&&&&&&&public&IEnumerator&GetEnumerator()//迭代器
&&&&&&&&&&&&return&s.GetEnumerator();
}-------------------------------------------------------StiAll.csusing&S
using&System.Collections.G
using&System.L
using&System.T
using&System.Threading.T
using&System.C
namespace&ConsoleApplication6
&&&&public&class&StiAll:IEnumerator
&&&&&&&&//student对象
&&&&&&&&Student&s;
&&&&&&&&//游标
&&&&&&&&int&i&=&-1;
&&&&&&&&public&StiAll(Student&ss)//构造函数,初始化student对象
&&&&&&&&&&&&this.s&=&
&&&&&&&&public&object&Current//获取当前的项(只读属性)
&&&&&&&&&&&&get&{&return&s.s[i];&}
&&&&&&&&public&bool&MoveNext()//将游标的位置向前移动
&&&&&&&&&&&&if&(i&s.s.Length-1)//如果在s数组的长度范围之内就返回true
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&i++;
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&&&&&else
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&public&void&Reset()//初始化游标
&&&&&&&&&&&&i&=&-1;
}-------------------------------------------------------主程序&Student&s&=&new&Student(new&string[]&{&"吕蒙",&"周泰",&"黄盖"&});//实例化Student对象
&&&&&&&&&&&&//第一种方式遍历
&&&&&&&&&&&&foreach&(var&item&in&s)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&Console.WriteLine(item);//输出吕蒙,周泰,黄盖
&&&&&&&&&&&&}
&&&&&&&&&&&&//第二种方式遍历
&&&&&&&&&&&&StiAll&sa&=&new&StiAll(s);
&&&&&&&&&&&&while&(sa.MoveNext())
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&Console.WriteLine(sa.Current);//输出吕蒙,周泰,黄盖
&&&&&&&&&&&&}
&&&&&&&&&&&&Console.ReadKey();本文出自 “” 博客,请务必保留此出处
了这篇文章
类别:┆阅读(0)┆评论(0)}

我要回帖

更多关于 c ienumerator 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信