今天看到一个用法,yield return <一个对象>。它不是等待这个对象不为空;经过询问及查询,这个对象其实是一个迭代器对象(协程也是一个迭代器)。
其实说迭代器什么的有点抽象,其实就是继承并实现了两个接口。
以下是自定义协程计时器。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TestSpace
{
public class CoroutineTest : MonoBehaviour
{
TestNode[] nds;
TestNode nd1 = new TestNode(1, 2f);
TestNode nd2 = new TestNode(2, 2f);
TestNode nd3 = new TestNode(3, 2f);
TestNode nd4 = new TestNode(4, 2f);
// Start is called before the first frame update
void Start()
{
nds = new TestNode[4] { nd1, nd2, nd3, nd4 };
StartCoroutine(Test());
}
private IEnumerator Test()
{
for(int i = 0;i < nds.Length;i ++)
{
Debug.Log(nds[i].nodeId);
yield return nds[i];
}
}
}
public class TestNode : IEnumerable<TestNode>, IEnumerator
{
public int nodeId;
public float waitTime;
public TestNode(int nodeid, float waittime)
{
nodeId = nodeid;
waitTime = waittime;
}
public IEnumerator<TestNode> GetEnumerator()
{
Debug.LogError("GetEnumerator1");
yield break;
}
IEnumerator IEnumerable.GetEnumerator()
{
Debug.LogError("GetEnumerator0");
return GetEnumerator();
}
bool init = false;
float endtime = -1f;
private bool IsTimeOver()
{
if(!init)
{
init = true;
endtime = Time.time + waitTime;
}
if(Time.time >= endtime)
{
Debug.Log("Time Up " + nodeId);
Reset();
return false;
}
else
{
return true;
}
}
public object Current { get { /*Debug.LogError("GetCurrent");*/ return null; } }
public bool MoveNext()
{
return IsTimeOver();
}
public void Reset()
{
Debug.LogError("Reset");
init = false;
endtime = -1f;
}
}
}
由第一篇文章可知,迭代器是有两个接口,
image.pngIEnumerable
和IEnumerator
。这俩玩意,继承第一个,需要实现GetIEnumerator
方法,来获得IEnumerator
元素。而IEnumerator
要实现获得当前、移到下一个、重置,三个方法;它就是迭代器!
运行了一下文章中此处的例子,断点调试发现,每次都需要MoveNext函数执行后,才会执行一次IEnumerable中内容,执行到return后返回,完成改次迭代。然后返回值会传入迭代器的Current内部。
image.png
秋雨总结
网友评论