foreach循环研究及迭代器
1.IEnumerable接口:
命名空间:System.Collections(System.Collections 命名空间包含接口和类,这些接口和类定义各种对象(如列表、队列、位数组、哈希表和字典)的集合。)
IEnumerable 包含单一方法 GetEnumerator,该方法返回 IEnumerator。
IEnumerator 提供了通过公开 Current 属性和 MoveNext 和 Reset 方法来循环访问集合的功能。
IEnumerable.GetEnumerator方法返回循环访问集合的枚举数,返回值为IEnumerator 对象。
最初,枚举数定位在集合中第一个元素的前面。 Reset 方法还将枚举器恢复到此位置。 在此位置,Current 属性是不确定的。 因此,在读取 Current的值之前,必须调用 MoveNext 方法将枚举器推进到集合的第一个元素。
2.foreach 循环的实现方式:
首先,使用foreach结构可以迭代一个数组,因为System.Array类实现了IEnumerable接口,这个接口的唯一方法GetEnumerator()可以迭代集合中的各项。
foreach循环迭代一个collectionObject集合的过程:
a,调用collectionObject.GetEnumerator(),返回一个IEnumerator引用,
b,调用所返回的IEnumerator接口的MoveNext()方法,
c,MoveNext返回true,就使用IEnumerator接口的Current属性来获取对象的一个引用,用于foreach循环,
d,重复前面两步,直到MoveNext()方法返回false为止,此时循环停止。
若需在类中进行这些操作,必须重写几个方法,跟踪索引,维护current属性,以及执行其他一些操作,一个较为简单的替代方法是使用迭代器。
3.迭代器
迭代器的定义是,它是一个代码块,按顺序提供了要在foreach块中使用的所有值。
一般情况下,这个代码块是一个方法,但也可以使用属性访问器和其他代码块作为迭代器。
无论代码块是什么,其返回类型都是有限的。而迭代器块的返回类型是前面提到的接口类型IEnumerable和Ienumerator。使用这两个类型的场合是:
a,如果要迭代一个类,可使用方法GetEnumerator(),其返回类型是IEnumerator。
b,如果要迭代一个类成员,例如方法,则使用IEnumerable。
在迭代器块中,使用yield关键字选择要在foreach循环中使用的值。
一个简单的迭代器(封装素数):
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Ch11Ex03
{
public class Primes
{
private long min;
private long max;
public Primes() : this(2,100) { }
public Primes(long minimum,long maximum)
{
if (minimum<2)
{
min = 2;
}
else
{
min = minimum;
}
max = maximum;
}
public IEnumerator GetEnumerator()
{
for (long possiblePrime = min; possiblePrime <=max; possiblePrime++)
{
bool isPrime = true;
for (long possibleFactor = 2; possibleFactor <=(long)Math.Floor(Math.Sqrt(possibleFactor)); possibleFactor++)
{
long remainderAfterDivision = possiblePrime % possibleFactor;
if (remainderAfterDivision==0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
yield return possiblePrime;
}
}
}
}
}
main函数执行:
static void Main(string[] args)
{
Primes primesFrom2To1000 = new Primes(2,1000);
foreach (long i in primesFrom2To1000)
{
Console.Write($"{i}");
}
Console.ReadKey();
//Console.WriteLine("Hello World!");
}
说明:此迭代器可以枚举上下限之间的素数集合。foreach循环执行in collention时,进入迭代器执行
collectionObject.GetEnumerator(),然后yield返回循环值。
如果把上下限设置为非常大的数,在程序执行时会发现,一次显示一个结果,中间有暂停,而不是一次显示所有结果。这说明,无论代码在yield调用之间是否终止,迭代器代码都会一次返回一个结果。如果在调试模式下运行代码,会发现调用yield会中断代码的执行,当请求一个值时,也就是使用迭代器的foreach循环开始一个新循环时,代码会恢复执行。
IEnumerator接口官方文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerator?view=netframework-4.8