扩大
缩小
  

C#基础之五--Foreach的原理

一、从编译器的角度自定义实现Foreach遍历

 1.自定义类型并使用foreach遍历

运行VS后编译器提示了错误,根据错误描述可以推断出foreach需要调用Person类型中的”GetEnumerator”方法。

2.在自定义类型中添加”GetEnumerator”方法

 

 根据编译器的错误提示,可以推断出Person类的GetEnumerator方法的返回值类型必须要有MoveNext方法和Current属性,示例中的object类型并没有MoveNext方法和Current属性。

3.添加MoveNext方法和Current属性

  编译器的错误提示要有MoveNext方法和Current属性,但是我们无法搞清楚这两个东西的具体实现形式,比如说MoveNext方法的返回值是什么样的?Current属性是只读还是可读可写的?

  此时我们可以去已经支持foreach的类型中查找GetEnumerator方法返回值类型,并对该类型的实现进行仿写并用于我们自定义类型当中。string类型作为常用类型并支持foreach遍历,下面我们查看该string的GetEnumerator方法返回值类型进行仿写。

 

 

 二、下面以“数数”的思想来真正实现foreach遍历的功能

1.遍历的数据对象

添加foreach“遍历的数据对象”后又有问题来了,foreach如何访问到这个数据呢。我们可以将数据作为“迭代计数器对象”构造函数的参数在GetEnumerator方法中传递过去,然后“迭代计数器对象”中提供一个字段进行存储。

2.设置foreach遍历到的当前元素(Current属性)

目前我们遍历的“对象”是一个string数组,所以要读取这个数组里的元素,我们需要一个下标索引来读取遍历到的当前元素,并作为Current属性值。下面我们将设置一个int类型值为-1的字段作为“读取下标”,然后在Current属性的get方法中通过下标索引器读取“当前遍历到的数据对象”。

3.MoveNext方法

  因为我们是通过下标去访问元素的,所以需要对下标进行递增进行变化,从而不断指向下一个元素从而到达累计。MoveNext方法是一个布尔的返回值类型,其主要目的是告知foreach当前遍历的数据对象是否还存在没有遍历到的元素,如果存在元素则不断递增下标索引并反会true,反之返回false并结束遍历,MoveNext方法的返回值相当于foreach遍历的前提条件。

  下面我们通过代码来实现MoveNext方法:

 

到目前为止我们已经将一个不具备foreach条件的自定义类型,通过自编码实现了foreach的基本要求。下面我们通过代码运行看看执行结果:

结果运行成功,并打印输出遍历的数据对象(Person中的数组)。

注意:遍历该数组我们并没有通过foreach直接对其进行的遍历,而是结合foreach的流程本质和基本要求来实现的遍历功能。

 三、总结:

通过调试结果我们可以总结下foreach遍历主要依靠三个流程:

  1. foreach调用当前遍历类型的GetEnumerator方法创建一个“迭代计数器对象”,并将遍历的数据作为参数传递到对象构造函数中。(获取迭代计数器对象)
  2. “迭代计数器对象”调用MoveNext方法将索引下标递增(第一次递增为0),如果递增下标大于数组长度则代表已经遍历完。(调用MoveNext方法)
  3. MoveNext方法返回true,代表还有元素需要遍历,使用当前下标在数据中获取元素并设置为Current属性值。(获取Current属性)

foreach的写法其实就是调用上面的代码片段,从而实现的一种“语法糖”。

posted @ 2022-09-15 17:23  风筝遇上风  阅读(538)  评论(0编辑  收藏  举报