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

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

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

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

public static CoroutineAwaiter<WaitForSeconds> GetAwaiter(this WaitForSeconds instruction)
{
CoroutineAwaiter<WaitForSeconds> awaiter = new CoroutineAwaiter<WaitForSeconds>(instruction);
return awaiter;
}

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

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

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

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

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

public class CoroutineAwaiter<T> : INotifyCompletion
where T : YieldInstruction
{
private T mValue;
private Action mOnCompleted; public bool IsCompleted => false; public CoroutineAwaiter(T value)
{
mValue = value;
} public T GetResult() => default; private IEnumerator CoroutineExec()
{
yield return mValue;
mOnCompleted();
} #region INotifyCompletion
void INotifyCompletion.OnCompleted(Action onCompleted)
{
mOnCompleted = onCompleted; CoroutineRunner.Instance.StartCoroutine(CoroutineExec());
}
#endregion
}

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实现简单的全局协程托管,仅测试用:

using UnityEngine;

public class CoroutineRunner : MonoBehaviour
{
private static CoroutineRunner sInstance;
public static CoroutineRunner Instance => sInstance; private void Awake()
{
sInstance = this;
}
}

最终使用代码如下:

public class Test1 : MonoBehaviour
{
public void Start()
{
_ = WaitForSecondsExecTest();
//绕过警告提示
} async Task WaitForSecondsExecTest()
{
Debug.Log("Waiting 1 second...");
await new WaitForSeconds(1f);
Debug.Log("Done!");
}
}

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

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

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

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

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

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

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

public class Test : MonoBehaviour
{
public class Result<T>//此处需有一个泛型才行
{
public int Select<TOut>(Func<T, TOut> selector)
{
return 12;
}
} private void Start()
{
Result<int> r = new Result<int>(); var rInt = from item in r
select new {item}; Debug.Log("rInt: " + rInt);
//return 12.
}
}

对于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. 使用google zxing生成二维码图片

    生成二维码工具类: 1 import java.awt.geom.AffineTransform; 2 import java.awt.image.AffineTransformOp; 3 impor ...

  2. 添加su权限

    在root用户下 visudo amy   ALL=(ALL)   NOPASSWD:ALL 在amy用户下 vim ~/.bashrc alias sd = "sudo"

  3. virtualenv笔记

    virtualenv venv --python=python2.7 mkvirtualenv venv --python=python linux中使用virtualenvwrapper 安装 pi ...

  4. IDEA常用优化设置

    1.设置鼠标悬浮提示 Editor->General 这里要勾选下,后面设置的是延迟时间 默认半秒:设置后,我们鼠标移动到类上看看: 2.显示方法分隔符 Editor->General - ...

  5. 寒武纪加速平台(MLU200系列) 摸鱼指南(二)--- 模型移植-环境搭建

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  6. 博主日常工作中使用的shell脚本分享

    前言: 今天给大家分享一篇在我工作中常用的一个shell脚本,里面有一些我们常用到的shell操作.该脚本用于本地电脑和服务器交互上,实现以下功能: 自动拉取自己个人电脑上的源码到服务器上yocto包 ...

  7. 1组-Alpha冲刺-3/6

    一.基本情况 队名:震震带着六菜鸟 组长博客:https://www.cnblogs.com/Klein-Wang/p/15544334.html 小组人数:7人 二.冲刺概况汇报 王业震 过去两天完 ...

  8. UML常用建模工具简介,安装方法和各自的优点

    这学期学习了统一建模语言,自己初学时对各种建模工具十分陌生,各种名词都不懂,软件也都不了解,开始很是不知所措.为了防止其他初学者陷入我的困境,自己对各种工具进行了总结: Visio:介绍:Visio是 ...

  9. Prometheus的监控解决方案(含监控kubernetes)

    prometheus的简介和安装 Prometheus(普罗米修斯)是一个开源系统监控和警报工具,最初是在SoundCloud建立的.自2012年成立以来,许多公司和组织都采用了普罗米修斯,该项目拥有 ...

  10. 生产者消费者模型及Golang简单实现

    简介:介绍生产者消费者模型,及go简单实现的demo. 一.生产者消费者模型 生产者消费者模型:某个模块(函数等〉负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.协程 ...