最近在看neuecc大佬写的一些库:https://neuecc.medium.com/,其中对await,async以及linq一些关键字实现了自定义化使用,

使其不需要引用对应命名空间,不需要多线程就可以做一些自定义操作。因此进行学习,并在Unity3D下进行测试。

1.await,async关键字的自定义化扩展

只需要实现GetAwaiter公共方法即可,通过扩展方法实现也可以:

  1. public static CoroutineAwaiter<WaitForSeconds> GetAwaiter(this WaitForSeconds instruction)
  2. {
  3. CoroutineAwaiter<WaitForSeconds> awaiter = new CoroutineAwaiter<WaitForSeconds>(instruction);
  4. return awaiter;
  5. }

该扩展方法可以实现Unity中的协程WaitForSeconds的异步封装。

这里看到会返回一个类型,实际上c#编译器关注返回的类型有没有实现INotifyCompletion接口

或ICriticalNotifyCompletion接口,这里以INotifyCompletion接口为例。

注意:此处代码参考Unity3dAsyncAwaitUtil(https://github.com/modesttree/Unity3dAsyncAwaitUtil)

对于返回类型,CoroutineAwaiter<WaitForSeconds>其实现如下:

  1. public class CoroutineAwaiter<T> : INotifyCompletion
  2. where T : YieldInstruction
  3. {
  4. private T mValue;
  5. private Action mOnCompleted;
  6.  
  7. public bool IsCompleted => false;
  8.  
  9. public CoroutineAwaiter(T value)
  10. {
  11. mValue = value;
  12. }
  13.  
  14. public T GetResult() => default;
  15.  
  16. private IEnumerator CoroutineExec()
  17. {
  18. yield return mValue;
  19. mOnCompleted();
  20. }
  21.  
  22. #region INotifyCompletion
  23. void INotifyCompletion.OnCompleted(Action onCompleted)
  24. {
  25. mOnCompleted = onCompleted;
  26.  
  27. CoroutineRunner.Instance.StartCoroutine(CoroutineExec());
  28. }
  29. #endregion
  30. }

c#对该接口的调用流程,参考知乎(https://zhuanlan.zhihu.com/p/121792448):

  1. 先调用t.GetAwaiter()方法,取得等待器a
  2. 调用a.IsCompleted取得布尔类型b
  3. 如果b=true,则立即执行a.GetResult(),取得运行结果;
  4. 如果b=false,则看情况:
    1. 如果a没实现ICriticalNotifyCompletion,则执行(a as INotifyCompletion).OnCompleted(action)
    2. 如果a实现了ICriticalNotifyCompletion,则执行(a as ICriticalNotifyCompletion).OnCompleted(action)
    3. 执行随后暂停,OnCompleted完成后重新回到状态机;

对于该接口的实现,这里不考虑同步情况一律算作异步,所以通过CoroutineRunner开启一个协程序,

并在协程执行完成后调用mOnCompleted,通知c#的异步可以往下执行了。

此处代码经过测试,全部是回调函数实现的等待,并不会导致线程堵塞。

CoroutineRunner实现简单的全局协程托管,仅测试用:

  1. using UnityEngine;
  2.  
  3. public class CoroutineRunner : MonoBehaviour
  4. {
  5. private static CoroutineRunner sInstance;
  6. public static CoroutineRunner Instance => sInstance;
  7.  
  8. private void Awake()
  9. {
  10. sInstance = this;
  11. }
  12. }

最终使用代码如下:

  1. public class Test1 : MonoBehaviour
  2. {
  3. public void Start()
  4. {
  5. _ = WaitForSecondsExecTest();
  6. //绕过警告提示
  7. }
  8.  
  9. async Task WaitForSecondsExecTest()
  10. {
  11. Debug.Log("Waiting 1 second...");
  12. await new WaitForSeconds(1f);
  13. Debug.Log("Done!");
  14. }
  15. }

2.Linq关键字的自定义化扩展

我们知道Linq可以写出类似Sql风格的关键字:

  1. int[] arr = new[] {1, 2, 3};
  2. var r = from item in arr
  3. where item > 0
  4. select item;

unirx中对其进行了自定义化扩展:

  1. // composing asynchronous sequence with LINQ query expressions
  2. var query = from google in ObservableWWW.Get("http://google.com/")
  3. from bing in ObservableWWW.Get("http://bing.com/")
  4. from unknown in ObservableWWW.Get(google + bing)
  5. select new { google, bing, unknown };
  6.  
  7. var cancel = query.Subscribe(x => Debug.Log(x));
  8.  
  9. // Call Dispose is cancel.
  10. cancel.Dispose();

研究了下它的代码,和GetAwaiter类似,只需要包含公共方法即可。

但是后来发现,类还必须包含一个泛型,C#编译器才可以成功识别:

  1. public class Test : MonoBehaviour
  2. {
  3. public class Result<T>//此处需有一个泛型才行
  4. {
  5. public int Select<TOut>(Func<T, TOut> selector)
  6. {
  7. return 12;
  8. }
  9. }
  10.  
  11. private void Start()
  12. {
  13. Result<int> r = new Result<int>();
  14.  
  15. var rInt = from item in r
  16. select new {item};
  17.  
  18. Debug.Log("rInt: " + rInt);
  19. //return 12.
  20. }
  21. }

对于where、skip等操作,应该也类似。

对于c#关键字自定义化的介绍就写到这里,至于怎么去用就仁者见仁智者见智了

这种写法最大的好处是不会引入System.Linq或是System.Threading等命名空间,

但如果要和多线程的异步混用或者用Task.WaitAll之类的操作,还是会引入很多多线程的东西。因此不建议混用。

对于Linq关键字和await,async异步关键字的扩展使用的更多相关文章

  1. C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较

    使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...

  2. 浅谈async、await关键字 => 深谈async、await关键字

    前言 之前写过有关异步的文章,对这方面一直比较弱,感觉还是不太理解,于是会花点时间去好好学习这一块,我们由浅入深,文中若有叙述不稳妥之处,还请批评指正. 话题 (1)是不是将方法用async关键字标识 ...

  3. 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]

    看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...

  4. 使用Async和Await进行异步编程(C#版 适用于VS2015)

    你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...

  5. Async 、 Await 的异步编程(.NET 4.5 新异步模型) [转自MSDN]

    使用异步编程,可以避免性能瓶颈和增强应用程序的总体响应能力. 但是,编写异步应用程序的以前的技术可能比较复杂,使它们难以编写,调试和维护. Visual Studio 2012 引入了一个简化的方法, ...

  6. 使用Async和Await进行异步编程(C#版 适用于VS2015) z

    你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...

  7. 使用 Async 和 Await 的异步编程 #Reprinted#

    异步方法容易编写 string urlContents = await client.GetStringAsync(); 以下特征总结了使上面一个异步方法. 方法签名包含一个 Async 或async ...

  8. Async和Await进行异步编程

    使用Async和Await进行异步编程(C#版 适用于VS2015) 你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很 ...

  9. 【C#复习总结】 Async 和 Await 的异步编程

    谈到异步,必然要说下阻塞,在知乎上看到了网友举的例子非常省动,在这里我引用下. 怎样理解阻塞非阻塞与同步异步的区别? 老张爱喝茶,废话不说,煮开水. 出场人物:老张,水壶两把(普通水壶,简称水壶:会响 ...

随机推荐

  1. Android现有工程使用Compose

    Android现有工程使用Compose 看了Compose的示例工程后,我们也想使用Compose.基于目前情况,在现有工程基础上添加Compose功能. 引入Compose 首先我们安装 Andr ...

  2. 【接口】SpringBoot+接口开发(一)

    一.接口的简单介绍 1.什么是接口:接口及服务: 2.接口的分类:(1)系统的内部接口;(2)第三方的外部接口; 3.简述接口原理图: 4.接口协议:是指客户端跟服务器之间或者接口与接口间进行的通讯时 ...

  3. Typecho 反序列化漏洞 分析及复现

    0x00 漏洞简介 CVE-2018-18753 漏洞概述: typecho 是一款非常简洁快速博客 CMS,前台 install.php 文件存在反序列化漏洞,通过构造的反序列化字符串注入可以执行任 ...

  4. Java8新特性Stream流应用示例

    Java8新特性介绍 过滤集合 List<String> newList = list.stream().filter(item -> item != null).collect(C ...

  5. idea使用git更新代码 : update project(git merge、git rebase)

    idea使用git更新代码 : 选中想要更新的项目,右键点击 git => repository => pull 这样使用一次后idea会自动建立选中分支的远程跟踪分支,以后可直接点击下图 ...

  6. 南京大学OS笔记(1)-应用眼中的操作系统

    南京大学OS笔记(1)-应用眼中的操作系统 早就想刷一刷南大JYY老师的os课.之前稍微看过几节,果然讲的风趣幽默,而且现场写代码展示水平确实很高,这次准备认真刷一刷然后好好记一下笔记.当然lab就不 ...

  7. 001.AD域控简介及使用

    一 AD概述 1.1 AD简介 域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系. 当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可 ...

  8. Python基础(类和实例)

    class Point(object): def __init__(self,name,score): self.__name = name self.__score = score def prin ...

  9. Vue组件传值prop验证方式

    在Vue组件开发过程中,父组件要经常给子组件传递数据,在传递数据的过程中,子组件可以使用prop来接收父组件传递的值,同时呢,我们可以为组件的 prop 指定验证要求,例如你知道的这些类型.如果有一个 ...

  10. requests_cookie登陆古诗文网。session的使用

    通过登录失败,快速找到登录接口 获取hidden隐藏域中的id的value值 # 通过登陆 然后进入到主页面 # 通过找登陆接口我们发现 登陆的时候需要的参数很多 # _VIEWSTATE: /m1O ...