C#学习之自定义类实现foreach

来源:互联网 发布:苹果怎么恢复备份数据 编辑:程序博客网 时间:2024/06/06 12:27

本文目的:通过实现 IEnumerable 接口,使得自定义类能使用foreach语句来遍历自身元素

前提知识:数组可以被foreach语句遍历数组中的元素,原因是所有数组的基类都是System.Array ,而System.Array 类实现了IEnumerable接口,可以通过GetEnumerator方法按需提供一个叫做枚举数(enumerator)的对象,枚举数可以依次返回请求的数组的元素。(注:C#里面的枚举数,也就是枚举器,类似于C++中的迭代器,而C#中的迭代器是另外一个意思。不知我这样理解对否?)

 

第一部分:通过继承IEnumerable接口实现foreach语句

第一步:创建Person类

 

复制代码
 1     public class Person 2     { 3         string Name; 4         int Age; 5  6         public Person(string name, int age) 7         { 8             Name = name; 9             Age = age;10         }11 12         public override string ToString()13         {14             return "Name:  " + Name + "\tAge:  " + Age;15         }16     }
复制代码


 第二步:创建PeopleEnum类,该类继承IEnumerator接口,实现IEnumerator接口里的MoveNext、Reset方法和Current属性

复制代码
 1     public class PeopleEnum : IEnumerator 2     { 3         private Person[] _people; 4         int position = -1; 5  6         public PeopleEnum(Person[] list) 7         { 8             _people = list; 9         }10 11         public bool MoveNext()12         {13             position++;14             return (position < _people.Length);15         }16 17         public void Reset()18         {19             position = -1;20         }21 22         public object Current23         {24             get25             {26                 return _people[position];27             }28         }29 30     }
复制代码

 

第三步: 创建People类,该类继承IEnumerable接口,实现了GetEnumerator方法,GetEnumerator方法的作用是获取枚举数(返回值是IEnumerator类型的,就是枚举数的类型),在这里是通过返回PeopleEnum类的一个实例来取得枚举数。

复制代码
 1     public class People : IEnumerable 2     { 3         private Person[] _people; 4         public People(Person[] pArray) 5         { 6             _people = new Person[pArray.Length]; 7             for (int i = 0; i < pArray.Length; i++) 8             { 9                     _people[i] = pArray[i];10                 11             }12         }13 14         public IEnumerator GetEnumerator()15         {16             return new PeopleEnum(_people);17         }18     }
复制代码

 

第四步:People类实现了接口IEnumerable接口,所以People类的实例就能使用foreach来遍历自身元素。主函数测试代码如下:

 

复制代码
 1     class Program 2     { 3         static void Main(string[] args) 4         { 5             Person[] persons = new Person[]  6             { 7                 new Person("aaa", 20), 8                 new Person("bbb", 21), 9                 new Person("ccc", 22)10             };11 12             People peopleList = new People(persons);13 14             foreach (var item in peopleList)15             {16                 System.Console.WriteLine(item);17             }18 19             System.Console.ReadKey();20         }21     }
复制代码

 

 

输出如下

 

第二部分:foreach实现的本质

第一部分里的第二步创建PeopleEnum类,并实现里其继承的IEnumerator接口里的MoveNext、Reset方法和Current属性,其实,该类已经具备了遍历自身元素的条件了。

把主函数里的测试的代码改成如下,运行-》输出,结果是一样的

View Code

 

但是不能使用foreach语句,为什么呢?因为使用foreach语句类必须提供GetEnumerator方法获取该类的枚举数,然后编译器通过这个枚举数来调用IEnumerator接口里的 MoveNext、Reset方法和Current属性实现对类元素的遍历。

给PeopleEnum类添加一个GetEnumerator方法

1         public IEnumerator GetEnumerator()2         {3             return this;4         }

 

主函数测试代码改成如下:

复制代码
 1     class Program 2     { 3         static void Main(string[] args) 4         { 5             Person[] persons = new Person[]  6             { 7                 new Person("aaa", 20), 8                 new Person("bbb", 21), 9                 new Person("ccc", 22)10             };11 12 13             PeopleEnum peopleEnum = new PeopleEnum(persons);14 15             foreach (var item in peopleEnum)16             {17                 System.Console.WriteLine(item);18 19             }20 21             System.Console.ReadKey();22         }23     }
复制代码

运行,成功!

结论:一个类想要实现foreach,就得提供GetEnumerator方法获取该类的枚举数(就是返回一个IEnumerator接口类型的变量)。实现GetEnumerator方法(或者称为获取枚举数)的方式有很多种,本文采用了实现IEnumerable接口的方式(本质上也就是实现IEnumerator接口,只不过把GetEnumerator方法挪出去了而已)。其他还有例如通过迭代器来实现GetEnumerator方法的方式,这个留到下一篇文章来说。谢谢!

原创粉丝点击