C#实现Unity协程

原理

  • 利用c#的yied特性,利用迭代器,在每一帧tick
  • IEnumerator 用来保存迭代状态,用于恢复迭代器中的代码执行点
  • unity中协程调用位置

普通迭代器

    //继承IEnumerable接口,其实也可以不继承这个接口,只要类里面含有返回IEnumberator引用的GetEnumerator()方法即可  
    class ForeachTest : IEnumerable
    {
        private string[] elements;  //装载字符串的数组  
        private int ctr = 0;  //数组的下标计数器  

        ///   
        /// 初始化的字符串  
        ///   
        ///   
        ForeachTest(params string[] initialStrings)
        {
            //为字符串分配内存空间  
            elements = new String[8];
            //复制传递给构造方法的字符串  
            foreach (string s in initialStrings)
            {
                elements[ctr++] = s;
            }
        }

        ///   
        ///  构造函数  
        ///   
        /// 初始化的字符串  
        /// 分隔符,可以是一个或多个字符分隔  
        ForeachTest(string initialStrings, char[] delimiters)
        {
            elements = initialStrings.Split(delimiters);
        }

        //实现接口中得方法  
        public IEnumerator GetEnumerator()
        {
            return new ForeachTestEnumerator(this);
        }

        private class ForeachTestEnumerator : IEnumerator
        {
            private int position = -1;
            private ForeachTest t;
            public ForeachTestEnumerator(ForeachTest t)
            {
                this.t = t;
            }

            #region 实现接口

            public object Current
            {
                get
                {
                    return t.elements[position];
                }
            }

            public bool MoveNext()
            {
                if (position < t.elements.Length - 1)
                {
                    position++;
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public void Reset()
            {
                position = -1;
            }

            #endregion
        }
    }

c#利用迭代器实现协程



    class MainEntry
    {
        static int frame = 0;

        static public IEnumerator WaitCoroutine()
        {
            Console.WriteLine("begin");
            yield return null;
            Console.WriteLine("Coroutine{0}", frame);
            yield return new WaitFream(10);
            Console.WriteLine("Coroutine{0}", frame);
            yield return null;
            Console.WriteLine("end");

        }

        //协程迭代5帧
        static public IEnumerator CoroutineDo5Frame()
        {
            while (true)
            {
                if(frame >= 5)
                {
                    break;
                }
                Console.WriteLine("CoroutineTick");
                yield return null;
            }
        }

        //等待给定帧数
        class WaitFream
        {
            int wait_count = 0;
            public WaitFream(int count)
            {
                wait_count = count;
            }
            public bool Tick()
            {
                return --wait_count > 0;
            }
        }

        static LinkedList CoroutineList = new LinkedList();
        static void StartCoroutine(IEnumerator enumerator)
        {
            CoroutineList.AddLast(enumerator);
        }

        static void CoroutineTick()
        {
            var node = CoroutineList.First;
            while(node != null)
            {
                IEnumerator cur_etor = node.Value;
                bool ret = true;
                if (cur_etor.Current is WaitFream)
                {
                    WaitFream wf = (WaitFream)cur_etor.Current;
                    if (!wf.Tick())
                    {
                        ret = cur_etor.MoveNext();
                    }
                }
                else
                {
                    ret = cur_etor.MoveNext();
                }
                //删除节点
                if(ret == false)
                {
                    CoroutineList.Remove(node);
                }
                node = node.Next;
            }
        }


        static void Main(string[] args)
        {
            // ForeachTest f = new ForeachTest("This is a sample sentence.", new char[] { ' ', '-' });  
            StartCoroutine(WaitCoroutine());
            StartCoroutine(CoroutineDo5Feam());
            while (true)
            {
                frema++;
                Console.WriteLine("trunk loop frame:{0}", frame);
                CoroutineTick();
                Console.ReadLine();
            }

        }
    }
}

yiled的原理

  • 仅仅是一个语法糖,用switch case 将不同yiled之间的代码块隔开,movenext时执行代码块并且改变到下一个执行状态,下次执行时将执行下一个代码块,将yield后面的值赋值给current值

  • 反编译语法糖展开代码

 class Program  
    {  
        static void Main(string[] args)  
        {  
            //这儿调用了方法。  
            var test = Power(2, 8, "");  
            Console.WriteLine("Begin to iterate the collection.");  
            //Display powers of 2 up to the exponent of 8:  
            foreach (int i in Power(2, 8, ""))  
            {  
                Console.Write("{0} ", i);  
            }  
            Console.ReadKey();  
        }  
        public static IEnumerable<int> Power(int number, int exponent, string s)  
        {  
            int result = 1;  
            if (string.IsNullOrEmpty(s))  
            {  
                Console.WriteLine("Begin to invoke GetItems() method");  
            }  

            for (int i = 0; i < exponent; i++)  
            {  
                result = result * number;  
                yield return result;  
            }  
            yield return 3;  
            yield return 4;  
            yield return 5;  
        }  
    }  
  • 反编译语法糖的代码
namespace ConsoleApplication2  
{  
    using System;  
    using System.Collections;  
    using System.Collections.Generic;  
    using System.Diagnostics;  
    using System.Runtime.CompilerServices;  

    internal class Program  
    {  
        private static void Main(string[] args)  
        {  
            IEnumerable<int> enumerable = Power(2, 8, "");  
            Console.WriteLine("Begin to iterate the collection.");  
            foreach (int num in Power(2, 8, ""))  
            {  
                Console.Write("{0} ", num);  
            }  
            Console.ReadKey();  
        }  

        public static IEnumerable<int> Power(int number, int exponent, string s)  
        {  
            d__0 d__ = new d__0(-2);  
            d__.<>3__number = number;  
            d__.<>3__exponent = exponent;  
            d__.<>3__s = s;  
            return d__;  
        }  

        [CompilerGenerated]  
        private sealed class d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable  
        {  
            private int <>1__state;  
            private int <>2__current;  
            public int <>3__exponent;  
            public int <>3__number;  
            public string <>3__s;  
            private int <>l__initialThreadId;  
            public int 5__2;  
            public int 5__1;  
            public int exponent;  
            public int number;  
            public string s;  

            [DebuggerHidden]  
            public d__0(int <>1__state)  
            {  
                this.<>1__state = <>1__state;  
                this.<>l__initialThreadId = Environment.CurrentManagedThreadId;  
            }  

            private bool MoveNext()  
            {  
                switch (this.<>1__state)  
                {  
                    case 0:  
                        this.<>1__state = -1;  
                        this.5__1 = 1;  
                        if (string.IsNullOrEmpty(this.s))  
                        {  
                            Console.WriteLine("Begin to invoke GetItems() method");  
                        }  
                        this.5__2 = 0;  
                        while (this.5__2 < this.exponent)  
                        {  
                            this.5__1 *= this.number;  
                            this.<>2__current = this.5__1;  
                            this.<>1__state = 1;  
                            return true;  
                        Label_009D:  
                            this.<>1__state = -1;  
                            this.5__2++;  
                        }  
                        this.<>2__current = 3;  
                        this.<>1__state = 2;  
                        return true;  

                    case 1:  
                        goto Label_009D;  

                    case 2:  
                        this.<>1__state = -1;  
                        this.<>2__current = 4;  
                        this.<>1__state = 3;  
                        return true;  

                    case 3:  
                        this.<>1__state = -1;  
                        this.<>2__current = 5;  
                        this.<>1__state = 4;  
                        return true;  

                    case 4:  
                        this.<>1__state = -1;  
                        break;  
                }  
                return false;  
            }  

            [DebuggerHidden]  
            IEnumerator<int> IEnumerable<int>.GetEnumerator()  
            {  
                Program.d__0 d__;  
                if ((Environment.CurrentManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))  
                {  
                    this.<>1__state = 0;  
                    d__ = this;  
                }  
                else  
                {  
                    d__ = new Program.d__0(0);  
                }  
                d__.number = this.<>3__number;  
                d__.exponent = this.<>3__exponent;  
                d__.s = this.<>3__s;  
                return d__;  
            }  

            [DebuggerHidden]  
            IEnumerator IEnumerable.GetEnumerator()  
            {  
                return this.System.Collections.Generic.IEnumerable.GetEnumerator();  
            }  

            [DebuggerHidden]  
            void IEnumerator.Reset()  
            {  
                throw new NotSupportedException();  
            }  

            void IDisposable.Dispose()  
            {  
            }  

            int IEnumerator<int>.Current  
            {  
                [DebuggerHidden]  
                get  
                {  
                    return this.<>2__current;  
                }  
            }  

            object IEnumerator.Current  
            {  
                [DebuggerHidden]  
                get  
                {  
                    return this.<>2__current;  
                }  
            }  
        }  
    }  
}  

才疏学浅,欢迎指正

你可能感兴趣的:(Unity)