先来说说IEnumrable和IEnumrator接口,IEnumrable接口成员如下:
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
IEnumrable是可枚举类型,什么是可枚举类型呢?简单说,就是实现了IEnumrable接口的类型,所有能用foreach循环的类型都是可枚举类型。
可迭代类型,迭代即遍历,可迭代,即可遍历,所以只要一个类型实现了IEnumrable接口,就可以进行对它进行迭代(遍历)。
这个接口只有一个成员GetEnumerator()方法,返回一个IEnumrator接口对象,我们再看看IEnumrator的接口定义:
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
IEnumrator枚举器,只有三个成员:只读属性Current,方法Move(),方法Reset()。
Reset()方法将集合游标复位至-1位置,为下一次向前遍历整个集合做准备;
Current只读属性,获取当前游标所在位置的集合元素;
MoveNext()方法,将游标移至下一个集合元素位置,为获取新元素做准备;
通过上面三个成员介绍,不难看出,如果我们创建一个集合类,实现IEnumrable接口的GetEnumrator()方法,再实现IEnumrator接口的三个成员:属性Current,方法Move(),方法Reset().就能实现对自定义集合对象的遍历.
一般来说有两种方式实现集合类的IEnumrable和IEnumrator接口成员,从而实现对集合类的元素遍历。
第一种,按照.Net集合类的接口实现方式,集合类继承IEnumrable接口并实现GetEnumrator()方法,方法内返回IEnumrator对象,然后创建一个类Enumrator_People,继承IEnumrator接口,实现该接口的三个成员.如下demo:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;namespace 自定义集合类
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){//People是自定义的集合类型,创建一个集合对象peo,然后将集合元素逐一添加进来,再进行peo集合遍历集合中的元素!//通过合类的无参构造函数,创建一个空集合对象peoPeople peo = new People();//通过Add方法添加集合元素peo.Add(new Person("LuSU"));peo.Add(new Person("ZhouYU"));//AddRange方法添加集合元素peo.AddRange(new Person[] { new Person("LiuBei"), new Person("SunQuan") });peo.AddRange(new List<Person> { new Person("CaoCao"), new Person("ZhuGeliang") });peo.RemoveAt(0);foreach (Person person in peo){Console.WriteLine(person.name);}Console.ReadKey();Console.WriteLine("\r\n");//利用构造函数初始化一个集合类对象List<Person> peopleList = new List<Person> { new Person("LI"), new Person("SA") };People people = new People(peopleList);foreach (Person person in people){Console.Write($"{person.name},");}Console.ReadKey();}}//自定义集合类的元素类型public class Person{public string name { get; set; }public Person(string name){this.name = name;}}//自定义集合类public class People : IEnumerable{static int _position = -1;private List<Person> _people = new List<Person>();public People(){}public People(List<Person> people){_people = people;}public void Add(Person per){_people.Add(per);}public void AddRange(IEnumerable<Person> personcollection){_people.AddRange(personcollection);}public void Remove(Person per){_people.Remove(per);}public void RemoveAt(int index){if(index < _people.Count)_people.RemoveAt(index);}public void RemoveRange(int Fromindex,int cnt){if (Fromindex + cnt <= _people.Count)_people.RemoveRange(Fromindex, cnt);}public void RemoveAll(){_people.Clear();}public object Current{get{return _people[_position];}}public bool MoveNext(){_position++;if (_position < _people.Count){return true;}else{return false;}}public void Reset(){_position = -1;}public IEnumerator GetEnumerator(){return new Enumrator_People(_people);}}public class Enumrator_People : IEnumerator{List<Person> _p;public Enumrator_People(List<Person> p){_p = p;}int _position = -1;public object Current{get{return _p[_position];}}public bool MoveNext(){_position++;if (_position < _p.Count){return true;}else{return false;}}public void Reset(){_position = -1;}}
}
运行demo,执行结果如下:
第二种,集合类继承IEnumrable和IEnumrator接口,并在集合类内实现这两个接口的所有成员,也能实现对自定义集合类对象的迭代,如下demo:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace 自定义集合类
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){List<Person> peopleList = new List<Person> { new Person("LI"), new Person("SA") };People people = new People(peopleList);foreach (Person person in people){Console.Write($"{person.name},");}Console.ReadKey();}}//自定义集合类的元素类型public class Person{public string name { get; set; }public Person(string name){this.name = name;}}//自定义集合类public class People : IEnumerator,IEnumerable{static int _position = -1;private List<Person> _p;public People(){}public People(List<Person> peo){_p = peo;}public object Current{get{return _p[_position];}}public IEnumerator GetEnumerator(){//this代表当前集合类,而当前集合类实现了IEnumrator接口,自然就可以把this作为IEnumrator对象返回给GetEnumrator方法.return this;}public bool MoveNext(){_position++;if (_position < _p.Count){return true;}else{return false;}}public void Reset(){_position = -1;}}
}
还有另一中实现IEnumrable接口内的GetIEnumrator()方法,从而返回Enumrator接口对象,在GetIEnumrator()方法内用关键字yield return返回集合元素。
yield关键字做了什么工作呢,通过代码示例可以看出,yield关键字是将return后面的内容,转换成了IEnumrator对象,返回给IEnumrator.
其实yield内部就是实现了IEnumrator接口的三个成员,我是这么理解的,这样就不用再额外写IEnumrator接口的三个成员的具体实现代码了,如下demo调试通过,奈斯!!!
using System;
using System.Collections;
using System.Collections.Generic;namespace 自定义集合类yield关键字
{class Program{static void Main(string[] args){List<Person> peopleList = new List<Person> { new Person("LI"), new Person("SA") };//调用显示实现的泛型接口方法IEnumerable<Person> people = new People(peopleList);Console.WriteLine(" IEnumerable<Person>接口对象显示实现集合类迭代:");foreach (Person person in people){Console.Write($"{person.name},");}Console.WriteLine("\r\n");//调用隐式实现的接口方法People peo = new People(peopleList);Console.WriteLine("People集合类对象隐式实现集合对象迭代:");foreach (Person person in people){Console.Write($"{person.name},");}Console.ReadKey();}}//自定义集合类的元素类型public class Person{public string name { get; set; }public Person(string name){this.name = name;}}//自定义集合类public class People : IEnumerable<Person>{private List<Person> _p;public People() { }public People(List<Person> peo){_p = peo;}//隐式实现IEnumrable接口,如果集合类型是People,调用该迭代器实现方法public IEnumerator GetEnumerator(){//用yield return返回,其实yield内部就是实现了IEnumrator接口的三个成员.//不知道这么理解对否,逻辑上是这样的,这样就不用再额外写IEnumrator接口的三个成员代码实现了,代码调试OK,奈斯!!!for (int i = 0; i < _p.Count; i++){yield return _p[i];}}//显示实现IEnumrable<Person>接口,,如果集合类型是IEnumrable<Person>,调用该迭代器实现方法IEnumerator<Person> IEnumerable<Person>.GetEnumerator(){foreach (var item in _p){yield return item;}}}
}
代码执行后的结果如下: