1.迭代器模式
迭代器模式指按照一定顺序来访问一个集合对象中的每个元素, 但是同时不会暴露集合对象的内部结构. C#中内置的迭代器模式就是Foreach语句, 它可以顺序遍历容器中的每个元素. 而迭代器的具体实现主要是靠IEnumerable 和IEnumerator.
2. IEnumerator
IEnumerator接口其实就是foreach的具体实现, 它只定义了三个函数, 如下
public interface IEnumerator
{
bool MoveNext();
object Current { get; }
void Reset();
}
也就是说我们实现一个最简单的IEnumerator接口只需要实现这三个函数即可. MoveNext()表示向集合中的下一个元素移动, 如果有下一个元素返回true, 没有就返回false. Current是一个只读属性, 返回当前迭代器所指元素. Reset()表示重置迭代器到第一个元素.
class MyIEnumerator: IEnumerator
{
private int count = 10;
public bool MoveNext()
{
--count;
return count >= 0;
}
public object Current
{
get { return count; }
}
public void Reset()
{
count = 10;
}
}
这就是一个简单的IEnumerator, 如果用Foreach输出, 可以得到从9到0的十个计数. 而具体的实现过程还需要IEnumerable.
3. IEnumerable
IEnumerable可以粗略的理解为可迭代(遍历)的, 如果接口继承了IEnumerable, 那么就可以使用Foreach语句进行迭代操作. 这个接口只定义了一个函数, 如下:
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
这个函数需要返回一个我们刚才定义的IEnumerator, 即告知上层调用方可以枚举.
class MyIEnumerable : IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyIEnumerator();
}
}
这个时候我们的迭代器已经实现, 可以使用Foreach语句进行迭代操作.
void Start()
{
foreach (var VARIABLE in new MyIEnumerable())
{
Debug.Log(VARIABLE);
}
}
此时运行程序, 可以得到我们想要的结果, 从9数到0, 共计10个数.
我们现在有一个完整的迭代器了, 但是有一个问题, 很多时候我们需要的迭代器并不复杂, 如上面的计数装置, 如果每次都需要实现IEnumerator和IEnumerable十分不方便, 显得头重脚轻, 这时我们可以使用yield.
4.yield
yield是为了方便使用迭代器而产生的语法糖, 他可以直接使用在返回类型为IEnumerable或IEnumerator的函数中直接实现迭代器操作. 它有两种用法yield break 和yield return (something) 效果和break与return一样. 当使用yield return在foreach语句中进行迭代器操作时, 每一次执行到yield return时都会返回后面定义的something并且记录函数内的信息, 下一次运行时继续.
void Start()
{
foreach (var VARIABLE in myIEnumerable())
{
Debug.Log(VARIABLE);
}
}
private IEnumerable myIEnumerable()
{
for (int i = 9; i >= 0; --i)
{
if (i == 5) yield break;
yield return i;
}
}
这里我们在i = 5的时候使用了yield break终止了迭代器操作, 如果去掉它, 这个函数就和我们刚才定义的迭代器作用一样, 产生了9到0, 共10个数的倒数.
5. 协程(coroutine)
除了foreach语句, Unity中另一种迭代器模式就是协程, 它是根据每一次IEnumerator的MoveNext()方法调用进行迭代的, 有些类似于Unity的Update方法. 同时它可以结合Unity的yield return new WaitForSeconds(time)等等接口实行迭代器+定时器模式.
使用和停止协程比较简单, 都只要传入IEnumerator就可以.
public Coroutine StartCoroutine(IEnumerator routine)
public void StopCoroutine(IEnumerator routine)
使用协程的方法实现我们的从9数到0.
void Start()
{
StartCoroutine(myCoroutine());
}
private IEnumerator myCoroutine()
{
for (int i = 9; i >= 0; i--)
{
Debug.Log(i);
yield return new WaitForSeconds(1f);
}
yield return StartCoroutine(myCoroutine());
}
值得注意的是unity里有很多可以和yield结合使用的语句块, 如上的代码不仅实现了从9数到0, 还实现了每隔1秒数一次, 数到0后继续从头开始数, 当然还有很多其他有趣的功能可以通过coroutine和yield实现.