c#迭代器及协程的本质

IEnumerator

这是一个接口,主要为了实现能够循环遍历,在子类中具体实现。包括以下几个方法:

public interface IEnumerator
{
  //移动到下一个
  bool MoveNext();
  //返回当前
  object Current { get; }
  //重置
  void Reset();
}

IEnumerable

这个接口很简单,就是定义了一个方法返回一个IEnumerator

 public interface IEnumerable
  {
    IEnumerator GetEnumerator();
  }

For循环的原理

for循环的原理很简单,只要循环的列表实现了IEnumerable,就是一个可迭代的对象。编译器就会帮我们转化为迭代器迭代

Person[] peopleArray = new Person[3]
{
    new Person("John", "Smith"),
    new Person("Jim", "Johnson"),
    new Person("Sue", "Rabon"),
};
People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
    print(p.firstName + " " + p.lastName);

//相当于这样迭代
var enumerator=peopleList.GetEnumerator();
while (enumerator.MoveNext())
{
    var  p =enumerator.Current;
    print(p.firstName + " " + p.lastName);
}

自定义迭代示例

public class Person
{
    public Person(string fName, string lName)
    {
        this.firstName = fName;
        this.lastName = lName;
    }

    public string firstName;
    public string lastName;
}

public class People : IEnumerable
{
    private Person[] _people;

    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];
        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public PeopleEnum GetEnumerator()
    {
        return new PeopleEnum(_people);
    }
}

public class PeopleEnum : IEnumerator
{
    private Person[] mPeople;

    private int index = -1;
    public PeopleEnum(Person[] people)
    {
        this.mPeople = people;
    }

    public bool MoveNext()
    {
        index++;
        return index < mPeople.Length;

    }

    public void Reset()
    {
        index = -1;
    }

    object IEnumerator.Current => Current;

    public Person Current
    {
        get
        {
            try
            {
                return mPeople[index];
            }
            catch (IndexOutOfRangeException e)
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

协程的本质

这里先说一下协程仍然是在一个线程上的,其执行过程类似于子函数。

我们在定义一个协程的时候,可以发现返回值就是一个IEnumerator,我们开启一个协程,其实是编译器背后会帮我们生成迭代器代码,然后再迭代器的Move里面进行切换代码,执行不同段的逻辑。

//StartCoroutine(CoroutineA());
 IEnumerator CoroutineA()
    {
        yield return new WaitForSeconds(1f);
        Debug.LogError("CoroutineA");
    }

下面以一个替代StartCoroutine的方法来帮助我们理解协程的本质:

StartCoroutine(TestStateChage().GetEnumerator());
//下面这段代码就相当于上面的StartCoroutine
// IEnumerable<int> iter = TestStateChage();
// IEnumerator iterator=iter.GetEnumerator();
// while (iterator.MoveNext())
// {
//     print($"当前数据{iterator.Current}");
// }

定义一个方法:

IEnumerable<int> TestStateChage()
{
    print("---我是TestStateChange的第一行代码");

    print("---我是第一个yield return 前的代码");
    yield return 1;
    print("我是第一个yield return 后的代码---");

    print("---我是第二个yield return 前的代码");
    yield return 2;
    print("我是第二个yield return 后的代码---");

}

如果我们使用Reflector反编译这段代码,实际上可以看出TestStateChage是生成了一个类,然后主要在MoveNext里面有三个状态,通过切换状态执行下一段代码。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KindSuper_liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值