重庆熊猫 Loading

.NET中的迭代器(Iterator)

更新记录
本文迁移自Panda666原博客,原发布时间:2021年6月30日。

一、迭代器介绍

C#2.0开始,我们可以使用迭代器(iterator)。编译器自动把我们定义的迭代器生成 可枚举类型 或 枚举器。迭代器需要System.Collections.Generic命名空间,要使用using引用它。

using System.Collections.Generic;

二、声明迭代器

迭代器看起来非常像一个方法,但实际上是有本质区别的。编译器将迭代器转换为私有类,然后在类中实现IEnumerable 或者 IEnumerator的方法,即会将其转为可迭代类型。迭代器可以包含在:方法、属性、索引器中。所以迭代器的返回类型只可能是以下四种类型:

System.Collection.IEnumerable
System.Collection.Generic.IEnumerable<T>
System.Collection.IEnumerator
System.Collection.Generic.IEnumerator<T>

在迭代器中通过yield return语句声明枚举中的下一项,枚举器不会一次返回所有元素,每次访问Current属性返回一个新值,iterator可以在method, property, indexer内实现。

实例:返回可枚举类型的迭代器

public class PandaTestClass
{
    public IEnumerable<string> GetEnumerator()
    {
        yield return "Panda";
        yield return "Cat";
        yield return "Dog";
        yield return "Monkey";
        yield return "Donkey";
    }
}

实例:返回枚举器的迭代器

public class PandaTestClass:IEnumerable<string>
{
    public IEnumerator<string> GetEnumerator()
    {
        yield return "Panda";
        yield return "Cat";
        yield return "Dog";
        yield return "Monkey";
        yield return "Donkey";
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

实例:可正序取数也可反向取数的迭代器

public class PandaTestClass
{
    private string[] animals { get; set; }

    public PandaTestClass()
    {
        this.animals = new string[]
        {
            "Panda",
            "Cat",
            "Dog",
            "Monkey",
            "Donkey"
        };
    }

    /// <summary>
    /// 正序访问
    /// </summary>
    /// <returns></returns>
    public IEnumerable<string> GetAnimal()
    {
        foreach (var item in this.animals)
        {
            yield return item;
        }
    }

    /// <summary>
    /// 反序访问
    /// </summary>
    /// <returns></returns>
    public IEnumerable<string> GetAnimalReverse()
    {
        var animalsReversed = this.animals.Reverse();
        foreach (var item in animalsReversed)
        {
            yield return item;
        }
    }
}

实例:在属性中定义迭代器

class PandaTestClass
{
    public IEnumerable<int> SomeProp
    {
        get
        {
            yield return 666;
            yield return 888;
            yield return 999;
        }
    }

    public IEnumerator<int> SomeProp2
    {
        get
        {
            yield return 666;
            yield return 888;
            yield return 999;
        }
    }
}

三、迭代器的内部状态
迭代器在编译器生成的枚举器中,没有实现Reset方法,所以不可以调用Reset。在后台编译器把迭代器转换为的枚举器类包含4个状态:

Before 首次调用MoveNext之前的状态
Running 调用MoveNext后进入这个状态
Supended 状态机等待下次调用MoveNext的状态
After 没有更多项可枚举

image

四、迭代器与异常处理

yield return语句不可以出现在try/catch/finally语句块中。原因是:迭代器在编译阶段会转为私有类型放在这些语句块中会导致异常复杂。但是可以放在try/finally语句块中。

实例:迭代器的异常处理

IEnumerable<string> Foo()
{
  try { yield return "One"; }    // OK
  finally { ... }
}
posted @ 2022-04-16 16:34  重庆熊猫  阅读(117)  评论(0编辑  收藏  举报