IEnumerator
这是一个接口,主要为了实现能够循环遍历,在子类中具体实现。包括以下几个方法:
public interface IEnumerator
{
//移动到下一个
bool MoveNext();
//返回当前
object Current {
get; }
//重置
void Reset();
}
IEnumerable
这个接口很简单,就是定义了一个方法返回一个IEnumerator
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
For循环的原理
for循环的原理很简单,只要循环的列表实现了IEnumerable,就是一个可迭代的对象。编译器就会帮我们转化为迭代器迭代
Person[] peopleArray = new Person[3]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon"),
};
People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
print(p.firstName + " " + p.lastName);
//相当于这样迭代
var enumerator=peopleList.GetEnumerator();
while (enumerator.MoveNext())
{
var p =enumerator.Current;
print(p.firstName + " " + p.lastName);
}
自定义迭代示例
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
}
public string firstName;
public string lastName;
}
public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public PeopleEnum GetEnumerator()
{
return new PeopleEnum(_people);
}
}
public class PeopleEnum : IEnumerator
{
private Person[] mPeople;
private int index = -1;
public PeopleEnum(Person[] people)
{
this.mPeople = people;
}
public bool MoveNext()
{
index++;
return index < mPeople.Length;
}
public void Reset()
{
index = -1;
}
object IEnumerator.Current => Current;
public Person Current
{
get
{
try
{
return mPeople[index];
}
catch (IndexOutOfRangeException e)
{
throw new IndexOutOfRangeException();
}
}
}
}
协程的本质
这里先说一下协程仍然是在一个线程上的,其执行过程类似于子函数。
我们在定义一个协程的时候,可以发现返回值就是一个IEnumerator,我们开启一个协程,其实是编译器背后会帮我们生成迭代器代码,然后再迭代器的Move里面进行切换代码,执行不同段的逻辑。
//StartCoroutine(CoroutineA());
IEnumerator CoroutineA()
{
yield return new WaitForSeconds(1f);
Debug.LogError("CoroutineA");
}
下面以一个替代StartCoroutine的方法来帮助我们理解协程的本质:
StartCoroutine(TestStateChage().GetEnumerator());
//下面这段代码就相当于上面的StartCoroutine
// IEnumerable<int> iter = TestStateChage();
// IEnumerator iterator=iter.GetEnumerator();
// while (iterator.MoveNext())
// {
// print($"当前数据{iterator.Current}");
// }
定义一个方法:
IEnumerable<int> TestStateChage()
{
print("---我是TestStateChange的第一行代码");
print("---我是第一个yield return 前的代码");
yield return 1;
print("我是第一个yield return 后的代码---");
print("---我是第二个yield return 前的代码");
yield return 2;
print("我是第二个yield return 后的代码---");
}
如果我们使用Reflector反编译这段代码,实际上可以看出TestStateChage是生成了一个类,然后主要在MoveNext里面有三个状态,通过切换状态执行下一段代码。