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


    本人初学C#,本文仅供个人整理思路用,那里说得不对,请大家多多指教,万分感激!

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

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

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

    第一步:创建Person类

    View Code
     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属性

    View Code
     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 Current
    23 {
    24 get
    25 {
    26 return _people[position];
    27 }
    28 }
    29
    30 }

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

    View Code
     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
     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 while (peopleEnum.MoveNext())
    13 {
    14 System.Console.WriteLine(peopleEnum.Current);
    15 }
    16
    17 System.Console.ReadKey();
    18 }
    19 }

    但是不能使用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方法的方式,这个留到下一篇文章来说。谢谢!

  • 相关阅读:
    nginx禁止ssl2和ssl3
    C#对图片进行缩放变换
    内网穿透
    雪花ID生成器
    .NET Core前后端分离快速开发框架(Core.3.1+AntdVue)
    【信息学奥赛一本通】题解目录
    【网络安全】ssh禁用弱秘钥交换算法和弱MAC算法
    Nginx Request Entity Too Large的解决方法
    docker进入当前正在运行容器
    IdentityServer4持久化到mysql数据库
  • 原文地址:https://www.cnblogs.com/zouzf/p/2362421.html
Copyright © 2020-2023  润新知