博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# 通过IEnumberable接口和IEnumerator接口实现泛型和非泛型自定义集合类型foreach功能...
阅读量:7027 次
发布时间:2019-06-28

本文共 5594 字,大约阅读时间需要 18 分钟。

IEnumerator和IEnumerable的作用

其实IEnumerator和IEnumerable的作用很简单,就是让除数组和集合之外的类型也能支持foreach循环,至于foreach循环,如果不清楚,请参考

代码如下:

static void Main(string[] args){       CatList cats = new CatList();       foreach (var cat in cats)       {            Console.WriteLine(cat.NickName);       }}public class CatList{       public string NickName { get; set; }       public int Age { get; set; }}

以上代码说明自定义集合类型(假设CatList是集合类型)是无法使用foreach进行循环的.

原因是C#中自定义集合类型要实现foreach的功能,必须通过IEnumerator和IEnumerable两个接口来实现!

 

1、通过IEnumerator和IEnumerable两个接口实现自定义集合类型的foreach循环功能.    非泛型版本

第一步:实现自定义集合类型实现IEnumerable接口,实现该接口的字面意思可以理解为:自定义集合类型实现了该接口,就拥有了"可枚举的功能".代码如下:

实现了IEnumerable接口之后,发现该接口规定必须返回一个IEnumerator接口(迭代器对象).ok,那么就必须返回一个IEnumerator,那么它是什么呢?别急,下面开始介绍这个接口!

 

第二步:通过IEnumerable要求实现的GetEnumerator()方法返回一个IEnumerator(迭代器对象),实现该接口必须实现以下三个方法/属性:

(1)、MoveNext()   ---将当前遍历的枚举数推进到集合的下一个.

注:如果 MoveNext 越过集合的末尾,则枚举数将被放置在此集合中最后一个元素的后面,而且 MoveNext 返回 false。当枚举数位于此位置时,对MoveNext 的后续调用也返回 false。如果最后一次调用 MoveNext 返回 false,则调用 Current 会引发异常。若要再次将 Current 设置为集合的第一个元素,可以调用 Reset,然后再调用 MoveNext

 

(2)、Current属性   ---返回正在遍历的集合中的元素,注:该属性没有set方法,所以在循环遍历的时候不能设置值.

(3)、Reset()   ---重置当前正在遍历的集合中元素的索引.

 

第三步:具体实现

在介绍完上面两个接口之后,开始具体的实现,现在需要编写一个People类,该类是一个Person集合,要求People类拥有foreach循环的功能,代码如下:

public class People : IEnumerable    {        private Person[] persons;        public People(Person[] persons)        {            Persons = persons;        }        public Person[] Persons { get => persons; set => persons = value; }        public IEnumerator GetEnumerator()        {            return new PersonEnum(Persons);        }        public class PersonEnum : IEnumerator        {            private Person[] perons;            private int _index=-1;            public PersonEnum(Person[] persons)            {                Perons = persons;            }            public object Current => Perons[_index];            public Person[] Perons { get => perons; set => perons = value; }            public bool MoveNext()            {                _index++;                if (_index < perons.Length)                    return true;                else                    return false;            }            public void Reset()            {                _index = 0;            }        }    }

 

 

第四步:验证代码,代码如下:

Person[] persons ={         new Person(){FirstName="Stephen",LastName="Curry"},         new Person(){FirstName="Lebron",LastName="James"},         new Person(){FirstName="Kobe",LastName="Brant"}};People people = new People(persons);foreach (var p in people){     Console.WriteLine(((Person)p).LastName);}

 

 

第五步:分析原理

总结分析下上面的代码,实现foreach代码的基本原理如下:

1、编写自定义集合类,实现IEnumerable接口,通过GetEnumerator()方法返回一个迭代器对象实例.

2、通过自定义集合类的构造函数,或者方法,或者属性(都可以),初始化一个类数组   !Important

3、将初始化完的类数组作为参数传递给迭代器类

4、编写迭代器类,create 构造函数,接收自定义集合类初始化完的类数组

5、实现IEnumerator(迭代器)接口,实现对应的三个方法,通过编写三个方法发现,其实迭代器就是简单的对数组进行的操作

 

第六步:执行自定义集合的循环

执行方式有两种:

(1)、foreach

Person[] persons ={      new Person(){FirstName="Stephen",LastName="Curry"},      new Person(){FirstName="Lebron",LastName="James"},      new Person(){FirstName="Kobe",LastName="Brant"}};People people = new People(persons);foreach (Person p in persons){        Console.WriteLine(p.LastName);}Console.ReadKey();

 

(2)、通过自定义集合类的GetEnumerator()方法

Person[] persons ={         new Person(){FirstName="Stephen",LastName="Curry"},         new Person(){FirstName="Lebron",LastName="James"},         new Person(){FirstName="Kobe",LastName="Brant"}};People people = new People(persons);IEnumerator er = people.GetEnumerator();while (er.MoveNext()){   Console.WriteLine(((Person)er.Current).LastName);}

分析两种不同的调用方式,foreach语句可以理解为是第二种方式的语法糖.

 

2、通过IEnumerable<T>和IEnumerator<T>实现自定义集合类,并实现简单的添加功能

class Program    {        static void Main(string[] args)        {            var list = new CustomList
(2); list.Add(1); list.Add(2); list.Add(2); var p = new int[] { 1, 2, 2 }; var list1 = new CustomList
(p); Console.WriteLine(list.Count+"..."+list1.Count); Console.ReadKey(); } } public class CustomList
: IEnumerable
{ private T[] _ts; private int _index = 0; public CustomList(T[] ts) { _ts = ts; _index = ts.Length; } public CustomList(int capcity) { _ts = new T[capcity]; } public int Count => _index; public void Add(T t) { if (_index >= _ts.Length) { //如果调用Add方法导致数组的长度大于我们给定的长度 //则创建一个新的数组,并将其长度扩大为原来的两倍 T[] newArr = new T[_ts.Length * 2]; //将原来数组中的数据拷贝到新的数组中 Array.Copy(_ts, newArr, _ts.Length); //使_ts指向新的数组 _ts = newArr; } _ts[_index++] = t; } public IEnumerator
GetEnumerator() { return new CustomEnumerator
(_ts); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class CustomEnumerator
: IEnumerator
{ private T[] _ts; private int _position = -1; public CustomEnumerator(T[] ts) { _ts = ts; } public T Current => _ts[_position]; object IEnumerator.Current => this.Current; public bool MoveNext() { _position++; if (_position < _ts.Length) return true; return false; } public void Reset() { _position = 0; } public void Dispose() { throw new NotImplementedException(); } }

 

转载于:https://www.cnblogs.com/GreenLeaves/p/7419541.html

你可能感兴趣的文章
仿淘宝头像上传功能(一)——前端篇。
查看>>
Eclipse通过集成svn实现版本控制
查看>>
OS开发过程中常用开源库
查看>>
关于在多个UItextield切换焦点
查看>>
STL: HDU1004Let the Balloon Rise
查看>>
hdu 2768
查看>>
git记住用户名密码
查看>>
ElasticSearch(2)-安装ElasticSearch
查看>>
从mysql数据表中随机取出一条记录
查看>>
ORACLE 锁表处理,解锁释放session
查看>>
二.hadoop环境搭建
查看>>
深海机器人问题
查看>>
ios开发之 -- invalid nib registered for identifier
查看>>
MySQL 通过semi join 优化子查询
查看>>
socket编程-服务器端
查看>>
L181 The microscopic structure of a cat’s tongue helps keep its fur clean
查看>>
django序列化单表的4种方法的介绍
查看>>
迭代(遍历)时候不可以使用集合的remove和add方法,但可使用Java迭代器的remove和add方法...
查看>>
记录MYSQL中SQL语句的一个坑.
查看>>
网页基础
查看>>