关于C#迭代器与Unity的Coroutine

问题
1.C#迭代器原理
2.Coroutine的返回类型为IEnumerator,使用yield return返回,它与迭代器有什么联系
3.实现一个Coroutine

1.迭代器的原理:
微软的官方文档:迭代器是C#2.0中的新功能,迭代器是方法、get访问器或运算符,使你能在类或结构体中支持foreach迭代,而不必实现整个 IEnumerable接口 ,只需提供一个迭代器,即可遍历类中的数据结构,当编译器检测到迭代器时,它将自动生成IEnumerable或IEnumerable<T>接口的 Current、MoveNext、Dispose 方法。迭代器使用 yield return 依次返回每个元素, yield break 终止迭代。迭代器的返回类型必须为 IEunmerable、IEnumerator 、IEnumerable<T>或IEnumerator<T>(前两个接口与后两个接口的区别是分别支持非泛型集合与泛型集合)
从中可以了解到:
C#1.0集合类的迭代需实现IEnumerable接口,IEnumerable接口:公开枚举数,该枚举数支持在非泛型集合进行简单迭代。它包含一个返回IEnumerator的GetEnumerator方法。再来看IEnumerator接口:枚举器,它提供了通过公开循环访问集合能力Current属性和MoveNext和Reset方法。
在C#1.0中,手动实现简单的foreach需要的做法如下,拿NGUI的BetterList<T>做实验:
它是使用的迭代器foreach:
T[] buffer;

改为使用IEnumerable<T>接口和IEnumerator<T>的实现方法:
将BetterList<T>继承IEnumerable<T>接口,此接口又是继承的IEnumerable接口,它增加了一个返回IEnumerator<T>的GetEnumerator方法。

新增一个继承IEnumerator<T>的类,IEnumerator<T>继承自IEnumerator, IDisposable,同时又新增了T Current属性。此类提供对泛型集合的循环访问的能力,每次迭代,执行过程如下
a.第一次迭代时游标position为-1
b.执行MoveNext,游标位置加1
c.返回Current,一般来说,Current属性都是只读的,所以这就是为什么在foreach时,不能修改集合内的item值。( 迭代器模式 :提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节)。
d.直到记录的position为迭代集合的长度,MoveNext返回false,执行Reset方法,将position重新设置为-1

在C#2.0时,通过yield语句简化迭代,微软官方对yield的解释:
yield return <expression>;
yield break;
yield 关键字向编译器指示它所在的方法是迭代器块。  编译器生成一个类 来实现迭代器块中表示的行为。 在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值。 这是一个返回值,例如,在 foreach 语句的每一次循环中返回的值。
yield return ,当迭代器遇到yield return时,会保存当前位置(也就是上面枚举器中维护游标),下次迭代的调用时,将从此位置重新开始执行。将计算的expression的结果以值的形式返回给迭代器对象。expression必须是可以隐式转换为迭代器的yield类型。
yield break ,将控制权无条件返回给迭代器的调用方,该调用方为枚举器对象的MoveNext方法或Dispose方法。
也就是说,编译器生成的那个类就是上面写的那个实现IEnumerator<T>接口的那个类。
2.Coroutine与迭代器
现在知道了StartCoroutine方法的参数是一个IEnumerator类型,那么在Unity协程中yield return返回的方法是隐式转换为迭代器类型,其实就是StartCoroutine对其中的IEnumerator进行MoveNext操作。
但即使如此,那么Unity如何通过返回WaitForSeconds实现延时呢,看Unity的继承关系,StartCoroutine函数返回一个Coroutine类型,而WaitForSeconds和Coroutine都是继承自YieldInstruction(是一个空类),WaitForSeconds也没有特殊的,它只包含一个seconds属性,真正的处理是在StartCoroutine中,如果发现其中的IEnumerator是个YieldInstruction类型,那么就会特殊处理。
这样如果扩展Coroutine可以通过继承YieldInstruction类来实现。
自己模仿实现一个简单Coroutine机制,也比较容易。
3.实现一个Coroutine
a.首先写一个Coroutine的空基类MYieldInstruction

b.写一个自己的延时类MWaitForSeconds

c.实现自定义的MStartCoroutine方法

d.test,将MCoroutineTest脚本挂在场景中

结果如下,有一点误差

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值