聊一聊Unity协程背后的实现原理

本文揭示了Unity协程背后的IEnumerator实现原理,讲解了yieldreturn与yieldbreak的区别,以及如何通过yield实现暂停和恢复执行。理解yield关键字与IEnumerator的关系有助于掌握异步编程的精髓。

Unity开发不可避免的要用到协程(Coroutine),协程同步代码做异步任务的特性使程序员摆脱了曾经异步操作加回调的编码方式,使代码逻辑更加连贯易读。然而在惊讶于协程的好用与神奇的同时,因为不清楚协程背后的实现原理,所以总是感觉无法完全掌握协程。比如:

  1. MonoBehaviour.StartCoroutine接收的参数为什么是IEnumeratorIEnumerator和协程有什么关系?
  2. 既然协程函数返回值声明是IEnumerator,为什么函数内yield return的又是不同类型的返回值?
  3. yield是什么,常见的yield returnyield break是什么意思,又有什么区别?
  4. 为什么使用了yield return就可以使代码“停”在那里,达到某种条件后又可以从“停住”的地方继续执行?
  5. 具体的,yield return new WaitForSeconds(3)yield return webRequest.SendWebRequest(),为什么可以实现等待指定时间或是等待请求完成再接着执行后面的代码?

如果你和我一样也有上面的疑问,不妨阅读下本文,相信一定可以解答你的疑惑。

IEnumerator是什么

根据微软官方文档的描述,IEnumerator是所有非泛型枚举器的基接口。换而言之就是IEnumerator定义了一种适用于任意集合的迭代方式。任意一个集合只要实现自己的IEnumerator,它的使用者就可以通过IEnumerator迭代集合中的元素,而不用针对不同的集合采用不同的迭代方式。

IEnumerator的定义如下所示

public interface IEnumerator
{
   
   
    object Current {
   
    get; }

    bool MoveNext();
    void Reset();
}

IEnumerator接口由一个属性和两个方法组成

  1. Current属性可以获取集合中当前迭代位置的元素
  2. MoveNext方法将当前迭代位置推进到下一个位置,如果成功推进到下一个位置则返回true,否则已经推进到集合的末尾返回false
  3. Reset方法可以将当前迭代位置设置为初始位置(该位置位于集合中第一个元素之前,所以当调用Reset方法后,再调用MoveNext方法,Curren值则为集合的第一个元素)

比如我们经常会使用的foreach关键字遍历集合,其实foreach只是C#提供的语法糖而已

foreach (var item in collection)
{
   
   
   Console.WriteLine(item.ToString());
}

本质上foreach循环也是采用IEnumerator来遍历集合的。在编译时编译器会将上面的foreach循环转换为类似于下面的代码

{
   
   
    var enumerator = collection.GetEnumerator();
    try
    {
   
   
        while (enumerator.MoveNext())  // 判断是否成功推进到下一个元素(可理解为集合中是否还有可供迭代的元素)
        {
   
   
            var item = enumerator.Current;
            Console.WriteLine(item.ToString());
        }
    } finally
    {
   
   
        // dispose of enumerator.
    }
}

yield和IEnumerator什么关系

yield是C#的关键字,其实就是快速定义迭代器的语法糖。只要是yield出现在其中的方法就会被编译器自动编译成一个迭代器,对于这样的函数可以称之为迭代器函数。迭代器函数的返回值就是自动生成的迭代器类的一个对象

试试想象如果没有yield关键字,我们每定义一个迭代器,就要创建一个类,实现IEnumerator接口,接口包含的属性与方法都要正确的实现,是不是很麻烦?而利用yield关键字,只需要下面简单的几行代码,就可以快速定义一个迭代器。诸如迭代器类的创建,IEnumerator接口的实现工作编译器通通帮你做了

// 由迭代器函数定义的迭代器
IEnumerator Test()
{
   
   
    yield return 1;
    Debug.Log("Surprise");
    yield return 3;
    yield break;
    yield return 4;
}
  1. yield return语句可以返回一个值,表示迭代得到的当前元素
  2. yield break语句可以用来终止迭代,表示当前没有可被迭代的元素了

如下所示,可以通过上面代码定义的迭代器遍历元素

IEnumerator enumerator = Test();  // 直接调用迭代器函数不会执行方法的主体,而是返回迭代器对象
bool ret = enumerator.
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值