• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
13
C#

迭代器

发表于 2022-04-13 • 字数统计 4760 • 被 1,522 人看爆

概念

迭代器是遍历容器的对象,尤其是列表

枚举器知识点

迭代器块

是有一个或多个yield语句的代码块

迭代器块语句是命令式,先执行代码块的第一个语句,然后执行后面的语句,最后控制离开块

特殊语句

  • yield return 语句指定了序列中返回的下一项
  • yield break 语句指定在序列中没有其它项

使用迭代器来创建枚举器


class MyClass
{
    //迭代器
    public IEnumerator<string> BlackAndWhite()
    {
        yield return "black";
        yield return "gray";
        yield return "white";
    }

    //返回枚举器
    public IEnumerator<string> GetEnumerator()
    {
        return BlackAndWhite();
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClass mc = new MyClass();
        foreach(string shade in mc)
        {
            Console.WriteLine(shade);
        }
        Console.ReadKey();
    }
}

结果

black
gray
white

使用迭代器来创建可枚举类型

class MyClass
{
    //迭代器
    public IEnumerable<string> BlackAndWhite()
    {
        yield return "black";
        yield return "gray";
        yield return "white";
    }

    //返回枚举器
    public IEnumerator<string> GetEnumerator()
    {
        IEnumerable<string> myEnumerable = BlackAndWhite();     //获取可枚举类型
        return myEnumerable.GetEnumerator();        //获取枚举器
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClass mc = new MyClass();
        foreach(string shade in mc)
        {
            Console.WriteLine(shade);
        }

        foreach (string shade in mc.BlackAndWhite())
        {
            Console.WriteLine(shade);
        }
        Console.ReadKey();
    }
}

结果

black
gray
white
black
gray
white

迭代器模式

  • 当我们实现返回枚举器的迭代器时,必须通过实现GetEnumerator来让类可枚举,它返回由迭代器返回的枚举器。如上面(使用迭代器创建枚举器)代码
  • 如果我们在类中实现迭代器返回可枚举类型,我们可以让类实现GetEnumerator来让类本身可被枚举,或不实现GetEnumerator,让类不可枚举。
    • 如果实现GetEnumerator,让它调用迭代器方法以获取自动生成的实现IEnumerable的类实例。然后,从IEnumerable对象返回由GetEnumerator创建的枚举器,如上面(使用迭代器创建可枚举类型)代码
    • 如果通过不实现GetEnumerator使类本身不可枚举,仍然可以使用由迭代器返回的可枚举类,只需要直接调用迭代器方法,如上面(使用迭代器创建可枚举类型)代码Main中第二个foreach

产生多个可枚举类型

class Spectrum
{
    string[] Colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };

    public IEnumerable<string> UVtoIR()
    {
        for(int i = 0; i < Colors.Length; i++)
        {
            yield return Colors[i];
        }
    }

    public IEnumerable<string> IRtoUV()
    {
        for (int i = Colors.Length - 1; i >= 0; i--)
        {
            yield return Colors[i];
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Spectrum spectrum = new Spectrum();
        foreach(string color in spectrum.UVtoIR())
        {
            Console.Write($"{color}, ");
        }

        Console.WriteLine();

        foreach(string color in spectrum.IRtoUV())
        {
            Console.Write($"{color}, ");
        }
        Console.WriteLine();

        Console.ReadKey();
    }
}

结果

violet, blue, cyan, green, yellow, orange, red,
red, orange, yellow, green, cyan, blue, violet,

将迭代器作为属性

声明两个不同的迭代器

class Spectrum
{
    bool _listFromUVtoIR;
    string[] Colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };
    public Spectrum(bool listFromUVtoIR)
    {
        _listFromUVtoIR = listFromUVtoIR;
    }

    public IEnumerator<string> UVtoIR
    {
        get
        {
            for(int i = 0; i < Colors.Length; i++)
            {
                yield return Colors[i];
            }
        }
    }

    public IEnumerator<string> IRtoUV
    {
        get
        {
            for (int i = Colors.Length - 1; i >= 0; i--)
            {
                yield return Colors[i];
            }
        }
    }

    public IEnumerator<string> GetEnumerator()
    {
        return _listFromUVtoIR ? UVtoIR : IRtoUV;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Spectrum startUV = new Spectrum(true);
        Spectrum startIR = new Spectrum(false);
        foreach(string color in startUV)
        {
            Console.Write($"{color}, ");
        }
        Console.WriteLine();

        foreach (string color in startIR)
        {
            Console.Write($"{color}, ");
        }
        Console.WriteLine();

        Console.ReadKey();
    }
}

迭代器实质

  • 迭代器需要System.Collections.Generic命名空间,因此我们需要使用using指令引入它。
  • 在编译器生成的枚举器中,Reset方法没有实现。而它是接口需要的方法,因此调用时总是抛出System.NotSupportedException异常。
  • 迭代器状态机
  • 迭代器状态机.png
  • Before首次调用MoveNext的初始状态。
  • Running调用NoveNext后进入这个状态。在这个状态中,枚举器检测并设置下一项的位置。在遇到yield return、yield break或在迭代器体结束时,退出状态。
  • Suspended状态机等待下次调用MoveNext的状态。
  • After没有更多项可以枚举。

如果状态机在Before或Suspended状态时调用了MoveNext方法,就转到了Running状态。在Running状态中,它检测集合的下一项并设置位置。
如果有更多项,状态机会转入Suspenided状态,如果没有更多项,它转人并保持在After状态。

分享到:
LINQ查询类型和子句
枚举器
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,090次看爆
  • JAVA_HOME环境配置问题 3,740次看爆
  • AssetBundle使用 3,508次看爆
  • VSCode配置C++开发环境 3,263次看爆
  • Lua反射 3,139次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图