c#学习笔记-------------------迭代器

学习笔记 / 2023-08-30 / 原文

 

一、什么是迭代器

迭代器(Iterator)又称光标(Cursor) 

提供一个方法顺序访问一个聚合对象的各个元素而不暴露内部标识 

迭代器可用作方法、运算符或 get 访问器的代码体。

迭代器提供明确的语法,用于指定如何迭代集合类中的数据,尤其是使用 foreach 循环。

这样一来,集合的最终用户就可以浏览其内部结构,而无需知道相应结构。

迭代器方法的返回值类型可以是以下4种接口类型中任意一种:

  • 位于命名空间System.Collections中的IEnumerable、IEnumerator
  • 位于命名空间System.Collections.Generic中的IEnumerable<T>、IEnumerator<T>

迭代器方法的内部使用状态机实现,但可以使用yield关键字快速实现迭代器方法,使用yield return语句添加需要迭代的元素,

在首次迭代时,会一直执行到第一个yield return语句并保存当前迭代状态,在接下来的每次迭代过程中都会从暂停的位置继续执行到下一个yield return语句并保存迭代状态(MoveNext()方法返回true并将当前迭代的值赋值给Current),

直到到达迭代器的结尾(MoveNext()方法返回false)完成本次迭代;

也可以在迭代过程中使用yield break语句立刻结束本次迭代

C# 2.0 新增了 yield 上下文关键字,这样类就可以更轻松地决定 foreach 循环如何迭代其内容。

二、使用迭代器

使用迭代器创建枚举器

namespace ConsoleApp2
{
    public class MyClass
    {
        /// <summary>
        /// 该类目前已实现GetEnumerator()使类本身可枚举
        /// </summary>
        /// <returns></returns>
        public IEnumerator<string> GetEnumerator()//迭代器
        {
            yield return "black";
            yield return "gray";
            yield return "white";
        }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            var mc = new MyClass();
            foreach (string shade in mc)////该类目前已实现GetEnumerator()使类本身可枚举 所以 写mc
            {
                Console.WriteLine(shade);
            }
            Console.ReadKey();
        }
    }
}
public class DaysOfTheWeek : System.Collections.IEnumerable
{
    string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };

    public System.Collections.IEnumerator GetEnumerator()
    {
        for (int i = 0; i < days.Length; i++)
        {
            yield return days[i];
        }
    }
}

class TestDaysOfTheWeek
{
    static void Main()
    {
        // Create an instance of the collection class
        DaysOfTheWeek week = new DaysOfTheWeek();

        // Iterate with foreach
        foreach (string day in week)
        {
            System.Console.Write(day + " ");
        }
    }
}

三、疑问记录

IEnumerator和IEnumerable 的区别是什么?

直观上的区别是在使用上面,c#规定foreach只能遍历IEnumerable,当我们foreach一个IEnumerator时,编辑器会提示错误:

 我们去遍历一个IEnumerator时,需要去循环地调用它的MoveNext()方法,然后.Current获取当前值。

 

yield关键字如何使用?

对于yield关键字,要看里面最关键的一个函数:MoveNext。

 

 MoveNext其实很简单,switch(1,2,3,4)的意思是顺序跳转,第一次进入MoveNext走分支1,第二次进入走分支2......以此类推。

而我们的yield关键字被分成了3步,刷新current值为yield的return值,刷新state值,如果还有下一个yield则返回true否则返回false。

 

迭代器的使用场景?

我们想要遍历一个对象的时候,就可以去实现一个IEnumrable或者IEnumrator。

yield关键字的使用场景,对于unity开发者,最棒的例子就是unity的协程啦。

unity的协程用迭代器来实现异步操作,比如yield return new WaitForSeconds(),等待多少s继续往下走。