协程与迭代器

news/发布时间2024/5/10 14:30:31

自己实现unity的协程功能_c#实现类似unity的协程-CSDN博客

前天和同事聊天,聊起来协程,聊起原理,什么迭代器,什么MoveNext

几句话带过之后就算完了,事后再次想起,发现自己已经忘了具体细节,于是也打算写成博客,供自己以后回应

一句话概括

(yield外部的)(会运行的)代码行,会被放到MoveNext()中

(写在yield return后面的类或者参数)会变成Current,Update每帧去调Current(判断是否能MoveNext),倘若返回了false,就不做任何事,否则就MoveNext()+新的初始化

具体代码+注释

查看代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;internal class Program
{static void Main(string[] args){MyMonoBehaviour objMyMonoBehaviour = new MyMonoBehaviour();Console.WriteLine("Create MyMonoBehaviour" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));objMyMonoBehaviour.StartCoroutine(CoroutineDetail());while (true){objMyMonoBehaviour.Update();Thread.Sleep(100);}}static IEnumerator CoroutineDetail(){Console.WriteLine("yield return null start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));yield return null;Console.WriteLine("yield return null end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));Console.WriteLine("wait 1.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));yield return new MyWaitForSeconds(1.0f);Console.WriteLine("wait 1.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));Console.WriteLine("wait 2.0 seconds start:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));yield return new MyWaitForSeconds(2.0f);Console.WriteLine("wait 2.0 seconds end:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));}
}public class MyMonoBehaviour
{public class RoutineInfo{//我的迭代器public IEnumerator routine;//迭代器当前需要比较的对象public MyYieldInstruction current;public bool IsCanMoveNext(){return current == null || current.IsCanMoveNext();}}//迭代器数据类ListList<RoutineInfo> lstRoutine = new List<RoutineInfo>();public void StartCoroutine(IEnumerator routine){//如果是空迭代器或者只能迭代一次的,直接返回if (routine == null || !routine.MoveNext()) return;//新建迭代数据类,管理该迭代器RoutineInfo objRoutineInfo = new RoutineInfo();lstRoutine.Add(objRoutineInfo);//初始化迭代数据类objRoutineInfo.routine = routine;SetRoutineInfo(ref objRoutineInfo);}//设置目标迭代器当前的迭代参数public void SetRoutineInfo(ref RoutineInfo objRoutineInfo){//yield后面不是new了一个类嘛,存到迭代器的Current里了,要拿到类,就在这设置一下objRoutineInfo.current = objRoutineInfo.routine.Current as MyYieldInstruction;}public void Update(){//从后往前遍历,便于lstRoutine.RemoveAt(i)for (int i = lstRoutine.Count - 1; i >= 0; i--){RoutineInfo item = lstRoutine[i];if (item == null) continue;if (!item.IsCanMoveNext()) continue;if (item.routine.MoveNext()) SetRoutineInfo(ref item);else lstRoutine.RemoveAt(i);//清除迭代完的迭代器}}
}//抽象类+抽象方法,有其他类型的迭代器就继承这个,判断条件由自己去实现
public abstract class MyYieldInstruction
{public abstract bool IsCanMoveNext();
}public class MyWaitForSeconds : MyYieldInstruction
{//在yield return时,记录等待时间,并用于后续的每次比较public float seconds;private DateTime beginTime;public MyWaitForSeconds(float seconds){this.seconds = seconds;beginTime = DateTime.Now;}//MyWaitForSeconds的比较就是//1.在初始化时记录开始时间和等待时间//2.使用当前时间减去开始时间,得到时间差//3.使用时间差去和等待时间比较,如果时间差>等待时间,就表示可以MoveNextpublic override bool IsCanMoveNext(){TimeSpan deltaSeconds = DateTime.Now - beginTime;bool res = deltaSeconds.TotalSeconds > seconds;Console.WriteLine("MyWaitForSeconds类内部比较一次,结果为" + res);return res;}
}

输出:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/05675471.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

Pedagogic metalanguage of Harry Potter

✨The images below is all from Harry Potter.Prominence(visual) 2.Size:small 3.Sharpness foreground color:Harry is out of focus and the snake is in focus 4.Address(visual): indirect gaze 5.Angle: no angle 6.Distance/shot:close shot 💡In this picture,Harry…

Kubernetes客户端认证(三)—— Kubernetes使用CertificateSigningRequest方式签发客户端证书

1、概述在《Kubernetes客户端认证(一)—— 基于CA证书的双向认证方式 》和《Kubernetes客户端认证(二)—— 基于ServiceAccount的JWTToken认证》两篇博文中详细介绍了Kubernetes客户端认证方式,包括以证书方式访问的普通用户或进程(运维人员及 kubectl、 kubelet 等进程)…

2-11. 背包数据初始化

创建 DataCollection创建 Enums种子、商品、家具 锄头(锄地)、砍树工具、砸石头工具、割草工具、浇水工具、菜篮子收割工具 被割的杂草创建 Inventory 文件夹 创建好 Inventory 文件夹,将 Item 文件夹放到 Inventory 文件夹下面,然后再创建 Data SO 文件夹,并在该文件夹下…

Notepad++ 如何调整显示字面大小

在 Notepad++ 上,可以使用 ctrl 加上鼠标的左键来滚动来进行调整。如何恢复默 可以使用 Ctrl 加数字键盘上的 / 键 来恢复默认设置。 当然也可以通过菜单栏上 view 菜单下的 Zoom 选项。上面的界面中可以看到我们的在 Notepad++ 中使用的选项。https://www.isharkfly.com/t/no…

Buddy编译器概述

Buddy编译器概述 Buddy编译器是一个特定于领域的编译器基础结构。使用buddy作为名称,希望构建一个buddy系统,帮助用户轻松设计、实现和评估特定领域的编译器。 Buddy Compiler社区是一个开源社区,在这里通过合作探索有趣的功能并实现编译器基础设施的想法 Buddy Compiler As…

FileZilla 链接服务器提示 20 秒连接超时

FileZilla 有个默认设置是如果 20 秒没有数据的话会自动中断链接。Command: Pass: **************** Error: Connection timed out after 20 seconds of inactivity Error: Could not connect to server修改配置 这个配置是可以修改的,修改的步骤为:Click Edit on Menu Click…