前一陣自己看了《unity腳本編程》其中講到了unity中協程的實現原理,講的比較難懂。我總結了給個基礎點的。
首先是c#中yield關鍵字
yield 關鍵字向編譯器指示它所在的方法是迭代器塊。 編譯器生成一個類來實現迭代器塊中表示的行爲。 在迭代器塊中,yield 關鍵字與 return 關鍵字結合使用,向枚舉器對象提供值。 這是一個返回值,例如,在 foreach 語句的每一次循環中返回的值。 yield 關鍵字也可與 break 結合使用,表示迭代結束。——msdn
msdn講的有點抽象,下面看看代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace YieldTest
{
class Program
{
static void Main(string[] args)
{
foreach (int i in Feige.Fei())
{
Console.WriteLine("返回的結果是:" + i );
}
}
class Feige
{
public static IEnumerable<int> Fei()
{
for (int i = 0; i < 10; i++)
{
yield return i;
Thread.Sleep(1000);
}
}
}
}
}
結果:
返回的結果是:0
返回的結果是:1
返回的結果是:2
返回的結果是:3
返回的結果是:4
返回的結果是:5
返回的結果是:6
返回的結果是:7
返回的結果是:8
返回的結果是:9
下面這種實現方式也是一樣的
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace YieldTest
{
class Program
{
static void Main(string[] args)
{
IEnumerator i = Feige.Fei();
while (i.MoveNext())
{
Console.WriteLine(i.Current);
Thread.Sleep(500);
}
Console.ReadLine();
}
class Feige
{
public static IEnumerator<int> Fei()
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}
}
}
}
模擬協程的實現代碼
using System.Collections;
using System.Collections.Generic;
namespace Com.Coroutine
{
public class Coroutine
{
internal IEnumerator m_Routine;
internal IEnumerator Routine
{
get { return m_Routine; }
}
internal Coroutine()
{
}
internal Coroutine(IEnumerator routine)
{
this.m_Routine = routine;
}
internal bool MoveNext()
{
var routine = m_Routine.Current as Coroutine;
if (routine != null)
{
if (routine.MoveNext())
{
return true;
}
else if (m_Routine.MoveNext())
{
return true;
}
else
{
return false;
}
}
else if (m_Routine.MoveNext())
{
return true;
}
else
{
return false;
}
}
}
// use this as a template for functions like WaitForSeconds()
public class WaitForCount : Coroutine
{
int count = 0;
public WaitForCount(int count)
{
this.count = count;
this.m_Routine = Count();
}
IEnumerator Count()
{
while (--count >= 0)
{
System.Console.WriteLine(count);
yield return true;
}
}
}
// use this as the base class for enabled coroutines
public class CoroutineManager
{
internal List<Coroutine> m_Coroutines = new List<Coroutine>();
// just like Unity's MonoBehaviour.StartCoroutine
public Coroutine StartCoroutine(IEnumerator routine)
{
var coroutine = new Coroutine(routine);
m_Coroutines.Add(coroutine);
return coroutine;
}
// call this every frame
public void ProcessCoroutines()
{
for (int i = 0; i < m_Coroutines.Count; )
{
var coroutine = m_Coroutines[i];
if (coroutine.MoveNext())
{
++i;
}
else if (m_Coroutines.Count > 1)
{
m_Coroutines[i] = m_Coroutines[m_Coroutines.Count - 1];
m_Coroutines.RemoveAt(m_Coroutines.Count - 1);
}
else
{
m_Coroutines.Clear();
break;
}
}
}
}
}