C#枚举器和迭代器

举报
步步为营 发表于 2023/03/14 14:19:42 2023/03/14
【摘要】 C#枚举器和迭代器

C#枚举器和迭代器

使用foreach语句时,可以依次取出数组里面的元素,原因就是数组提供了“枚举器(Enumerator)”,枚举器知道元素的位置并返回请求项。

枚举器IEnumerator

枚举器实现了IEnumerator接口,该接口中有Current属性、MoveNext和Reset方法,foreach实现原理类似如下代码:

static void Main(string[] args)
{
    int[] MyArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    //可枚举类实现了GetEnumerator方法,获取枚举器
    IEnumerator ie = MyArray.GetEnumerator();
    while ( ie.MoveNext())
    {
        int i = (int)ie.Current;
        Console.WriteLine(i);
    }
}

示例

  1. 定义一个可枚举类
class Colors : IEnumerable
{
    string[] colors = { "blue", "red", "yellow" };

    public IEnumerator GetEnumerator()
    {
        return new ColorEnumerator(colors);
    }
}

  1. 定义可枚举类中使用到的枚举器
class ColorEnumerator : IEnumerator
{
    string[] colors;
    int positon = -1;
    public ColorEnumerator(string[] colors)
    {
        this.colors = colors;
        for (int i = 0; i < colors.Length; i++)
        {
            this.colors[i] = colors[i];
        }
    }

    public object Current
    {
        get
        {
            if (positon == -1 || positon >= colors.Length) throw new InvalidOperationException();
            return colors[positon];
        }
    }

    public bool MoveNext()
    {
        if(positon <colors.Length-1)
        {
            positon++;
            return true;
        }
        else
        {
            return false;
        }
    }

    public void Reset()
    {
        positon = -1;
    }
}
  1. 使用可枚举类
static void Main(string[] args)
{
    Colors colors = new Colors();
    foreach (var item in colors)
    {
        Console.WriteLine(item);
    }
    Console.Read();
}

image.png

泛型枚举器

IEnumerator<T>

泛型枚举器与普通枚举器类似,不同之处在于普通枚举器的Current属性是Object类型,在取出是需要进行转化(看上面while代码块中的代码),而泛型可以直接返回指定的类型。

迭代器

迭代器使用

迭代器简化了可枚举器和可枚举类型的编码工作。yield return 表示依次返回枚举中的下一项。

如何要实现上面的实例,只需要实现可枚举类:

class Colors 
{
    string[] colors = { "blue", "red", "yellow" };

    public IEnumerator GetEnumerator()
    {
        return GetColorsEnumerator();
    }
	//返回枚举器
    public  IEnumerator<string> GetColorsEnumerator()
    {
        yield return "blue";
        yield return "red";
        yield return "yellow";
    }
}

结果与上面示例完全相同

常见迭代器模式

  1. 迭代器返回枚举器
class Colors
{
    public IEnumerator GetEnumerator()
    {
        return GetColors();
    }
	//该出返回的是枚举器
    public  IEnumerator<string> GetColors()
    {
        yield return ..;
        yield return ..;
        ...
    }
}
Colors colors = new Colors();
foreach (var item in colors)
{
     Console.WriteLine(item);
}
  1. 迭代器返回可枚举类型
class Colors
{
    //可以选择不实现该方法,让Colors类变成不可枚举类
    public IEnumerator GetEnumerator() 
    {
        return GetColors().GetEnumerator();
    }
	//该出返回的是可枚举类型
    public  IEnumerable<string> GetColors()
    {
        yield return ..;
        yield return ..;
        ...
    }
}
Colors colors = new Colors();
//如果实现GetEnumerator()方法,则使用以下方法
foreach (var item in colors)
{
     Console.WriteLine(item);
}
//如果没有实现GetEnumerator()方法,则使用以下方法
foreach (var item in colors.GetColors())
{
     Console.WriteLine(item);
}

多个迭代器

上面讲的迭代器有两种模式,为什么需要第2种方式?答案时候第2中方式更加灵活,比如可以实现多个迭代器

class Colors 
{
    string[] colors = { "blue", "red", "yellow" };


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

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

使用

static void Main(string[] args)
{
    Colors colors = new Colors();
    foreach (var item in colors.A())
    {
        Console.WriteLine(item);
    }
    Console.WriteLine("--------------");
    foreach (var item in colors.B())
    {
        Console.WriteLine(item);
    }
    Console.Read();
}

image.png

迭代器作为属性

上面的迭代器是作为方法,可以将方法封装为属性,方便调用

class Colors
{
    string[] colors = { "blue", "red", "yellow" };


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

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

使用方式基本相同,只不过是将方法调用改成了属性

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。