迭代器
只有实现了IEnumerable的类(可枚举类型)才可以使用foreach进行遍历;
Array、ArrayList、List等属于可枚举类型;
IEnumerable[可枚举类型接口]
IEnumerator[枚举类型接口]
只要一个类继承了可枚举类型接口,并且实现了可枚举类型接口中的成员,那么这个类叫做可枚举类型。
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}
Current: 只读的属性,返回的是objecj类型的引用,第一次位置为-1
MoveNext: 把枚举器位置 移动到下一项 bool表示 新位置是否有效
Reset: 把位置重置到初始状态
案例
使用枚举器的方式遍历数组
private void Start()
{
int[] array = { 10, -90, 1, 2, 3, 4, 5, 6 };
IEnumerator ie = array.GetEnumerator();
while (ie.MoveNext())
{
int x = (int)ie.Current;
print(x);
}
}
自定义一个迭代器
public class Test : MonoBehaviour
{
private void Start()
{
// 迭代器
object[] datas = { true, 100, 19, false, 'd', "df" };
MyIEnumerable me = new MyIEnumerable(datas);
foreach (object o in me)
{
print(o);
}
}
}
/// <summary>
/// 自定义的可枚举类型
/// </summary>
public class MyIEnumerable : IEnumerable
{
public object[] Values;
public MyIEnumerable(object[] values)
{
Values = values;
}
public IEnumerator GetEnumerator()
{
return new MyIEnumerator(this);
}
}
public class MyIEnumerator : IEnumerator
{
private int _position;
private MyIEnumerable _data;
public bool MoveNext()
{
if (_position != _data.Values.Length)
_position++;
return _position < _data.Values.Length;
}
public MyIEnumerator(MyIEnumerable mie)
{
_data = mie;
_position = -1;
}
public void Reset()
{
_position = -1;
}
public object Current
{
get
{
if (_position == -1 || _position == _data.Values.Length)
{
return null;
}
return _data.Values[_position];
}
}
}
更简单自定义的迭代器
public class Test : MonoBehaviour
{
private void Start()
{
MyIEnumerable me = new MyIEnumerable();
foreach (int i in me)
{
print(i);
}
}
}
public class MyIEnumerable
{
public IEnumerator<int> GetEnumerator()
{
yield return 100;
yield return 200;
yield return 300;
yield return 400;
yield return 500;
}
}
yield return 详解
可以根据返回值类型,告诉编辑器 创建可枚举类型 or 枚举器类型,指定了枚举器 对象下一个可枚举项
迭代器的执行顺序
当创建完一个可枚举类型(不管是手动实现 还是迭代器 创建)
枚举器 实际上可以看成是四种状态的状态机
Before 首次调用MoveNext之前的状态
初始位置在第一个可枚举之前
Running状态下,枚举器 检测下一项的位置
当遇到yield return 时 会进入 挂起状态, 知道遇到下一个 MoveNext()
当遇到yield break 时 或 迭代器主题结束,会进入退出状态
Suspended挂起状态
等待下一次MoveNext调用时 继续唤醒
After 已经到最后的位置,没有可枚举项