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里面有三个状态,通过切换状态执行下一段代码。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/KindSuper_liu/article/details/124531169
今日推荐