对于Linq关键字和await,async异步关键字的扩展使用
最近在看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):
- 先调用
t.GetAwaiter()方法,取得等待器a;- 调用
a.IsCompleted取得布尔类型b;- 如果
b=true,则立即执行a.GetResult(),取得运行结果;- 如果
b=false,则看情况:
- 如果
a没实现ICriticalNotifyCompletion,则执行(a as INotifyCompletion).OnCompleted(action)- 如果
a实现了ICriticalNotifyCompletion,则执行(a as ICriticalNotifyCompletion).OnCompleted(action)- 执行随后暂停,
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异步关键字的扩展使用的更多相关文章
- C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新 使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和 ...
- 浅谈async、await关键字 => 深谈async、await关键字
前言 之前写过有关异步的文章,对这方面一直比较弱,感觉还是不太理解,于是会花点时间去好好学习这一块,我们由浅入深,文中若有叙述不稳妥之处,还请批评指正. 话题 (1)是不是将方法用async关键字标识 ...
- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic)[msdn.microsoft.com]
看到Microsoft官方一篇关于异步编程的文章,感觉挺好,不敢独享,分享给大家. 原文地址:https://msdn.microsoft.com/zh-cn/library/hh191443.asp ...
- 使用Async和Await进行异步编程(C#版 适用于VS2015)
你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...
- Async 、 Await 的异步编程(.NET 4.5 新异步模型) [转自MSDN]
使用异步编程,可以避免性能瓶颈和增强应用程序的总体响应能力. 但是,编写异步应用程序的以前的技术可能比较复杂,使它们难以编写,调试和维护. Visual Studio 2012 引入了一个简化的方法, ...
- 使用Async和Await进行异步编程(C#版 适用于VS2015) z
你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很困难. VS2012介绍了简单的方法,那就是异步编程,它在.Net F ...
- 使用 Async 和 Await 的异步编程 #Reprinted#
异步方法容易编写 string urlContents = await client.GetStringAsync(); 以下特征总结了使上面一个异步方法. 方法签名包含一个 Async 或async ...
- Async和Await进行异步编程
使用Async和Await进行异步编程(C#版 适用于VS2015) 你可以使用异步编程来避免你的应用程序的性能瓶颈并且加强总体的响应.然而,用传统的技术来写异步应用是复杂的,同时编写,调试和维护都很 ...
- 【C#复习总结】 Async 和 Await 的异步编程
谈到异步,必然要说下阻塞,在知乎上看到了网友举的例子非常省动,在这里我引用下. 怎样理解阻塞非阻塞与同步异步的区别? 老张爱喝茶,废话不说,煮开水. 出场人物:老张,水壶两把(普通水壶,简称水壶:会响 ...
随机推荐
- hdu 5101 Select (二分+单调)
题意: 多多有一个智商值K. 有n个班级,第i个班级有mi个人.智商分别是v1,v2,.....vm. 多多要从这些人中选出两人.要求两人智商和大于K,并且两人不同班.问总共有多少种方案. 数据范围: ...
- 【网络好文】---MySQL为Null导致的四大坑
正式开始之前,我们先来看下 MySQL 服务器的配置和版本号信息,如所示: select version(); -- 版本为 8.0.22 "兵马未动粮草先行",看完了相关的配置之 ...
- Linux初学者:从不同角度理解Linux系统
在我初学Linux系统时,虽然已经掌握了一些命令,但总觉得还是很混乱.大家新买的笔记本如果是Windows系统,那么第一件事往往就是分区,目的就是将系统和软件分开.然而Linux却没有类似于Windo ...
- Linux&C open creat read write lseek 函数用法总结
一:五个函数的参数以及返回值. 函数 参数 返回值 open (文件名,打开方式以及读 ...
- vscode + vim 全键盘操作高效搭配方案
基础知识 vscode-vim vscode-vim是一款vim模拟器,它将vim的大部分功能都集成在了vscode中,你可以将它理解为一个嵌套在vscode中的vim. 由于该vim是被模拟的的非真 ...
- dotnet 6 使用 CreateSymbolicLink 创建文件夹符号链接
本文告诉大家如何使用 dotnet 6 提供的 Directory.CreateSymbolicLink 和 File.CreateSymbolicLink 方法创建文件夹和文件的符号链接 Direc ...
- JavaScript 对象:String & Array 及其常见应用
String对象 split 功能:把字符串分割为字符串数组.官方文档已经描述的够清楚,不多赘述.主要说一下需要注意的情况以及应用 1.省略分割参数 var str="How are you ...
- PTA 7-2 哈夫曼编码 (30分)
PTA 7-2 哈夫曼编码 (30分) 给定一段文字,如果我们统计出字母出现的频率,是可以根据哈夫曼算法给出一套编码,使得用此编码压缩原文可以得到最短的编码总长.然而哈夫曼编码并不是唯一的.例如对字符 ...
- js 事件流和事件冒泡阻止
js 事件流和事件冒泡阻止 事件流 当浏览器发展到第四代的时候(IE4与Netscape4)浏览器开发团队遇到一个有意思的的问题: 页面的哪一部分会拥有某个特定的事件? 比如在纸上画上一组同心圆,如果 ...
- Docker多机网络
前言 前面的文章主要聚焦于单机网络上,对于生产环境而言,单机环境不满足高可用的特点,所以是不具备上生产的条件,因此在开始Docker Swarm篇的时候我们先来聊聊多机网络之间Docker的通信如何做 ...