这篇文章主要来介绍一下C#中迭代器的相关知识,话不多说直接开始。
迭代器的定义
定义一个迭代器需要满足以下几个条件:
- 迭代器需用yield关键字来定义,有yield return和yield break两种形式。
- 迭代器的主体必须是函数、运算符、get访问器。
- 迭代器的返回类型必须是IEnumerable、IEnumerable<T>、IEnumerator、IEnumerator<T>类型。
public IEnumerator<int> MyEnumerator()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield break;
}
上面就是一个迭代器的具体定义方式。迭代器返回的yield类型为objec类型。这里需要说一下的是,yield虽然用来定义迭代器关键字,但yield不是编译器的保留字,所以依然可以用yield定义变量、函数等,但强烈不建议这么做。
迭代器在调用MoveNext()函数的时候才会执行迭代器函数,关于MoveNext()函数后面会讲到。当执行到yield return时会返回结果,并暂停保留当前当前代码中的位置。当下一次执行MoveNext()的时候则会从暂停位置重新开始执行。如要终止迭代的话则可以使用yield break。
迭代器的使用
在介绍迭代器的使用之前先简单介绍一下IEnumerator和IEnumerable中的函数和属性。
在IEnumerator中有几个需要知道的函数和属性:
- Current:用于获取到当前位置上的元素。
- MoveNext():将迭代器推进到下一个元素。
- Reset():重置迭代器,将迭代器位置设置到第一个元素之前。
这三个成员在使用迭代器时经常使用到的。
IEnumerable中的函数则少的多:
- GetEnumerator():获取集合中的IEnumerator。
IEnumerator<int> enumerator = MyEnumerator();
while(enumerator.MoveNext()) {
Console.WriteLine(enumerator.Current);
}
MyEnumerator函数接前一个例子,在上面这个示例中,第1行IEnumerator<int> enumerator = MyEnumerator();只是获取到了迭代器,并没有开始执行迭代器中的代码,只有当调用了MoveNext()的时候才开始执行。并且在MoveNext()函数执行之前,Current中的值是默认值,在执行MoveNext()之后才获取到当前数值。MoveNext()在执行到yield return时会返回为ture,只有当迭代器执行完或yield break时才会返回false。
除了传统的do、while、for这些迭代语句可以用来执行迭代器,C#中还有专门用于迭代器的foreach语句。
public IEnumerable<int> MyEnumerable()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
}
public void Function()
{
IEnumerable<int> enumerable = MyEnumerable();
foreach(int number in enumerable) {
Console.WriteLine(number);
}
}
上面就是一个foreach的使用示例,foreach接收的参数必须是IEnumerable和IEnumerable<T>类型。使用foreach的效果和传统迭代语句是等价的,MoveNext()函数由系统进行调用,Current值则就是示例当中的number变量。foreach也是一种语法糖衣,代码在编译后会展开成while的形式,具体细节看文章最后给的官网链接。
foreach经常会使用在容器的遍历上,在使用foreach遍历容器时修改容器则会造成报错。
最后给到关于迭代器的官方文档,有关迭代器以及C#更多的疑问可以直接查阅官方文档。
迭代器:https://docs.microsoft.com/zh-cn/dotnet/csharp/iterators
yield关键字:https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/yield
IEnumerator:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.generic.ienumerator-1?view=netframework-4.7.2
IEnumerable:https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.ienumerable?view=netframework-4.7.2