对于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 的异步编程
谈到异步,必然要说下阻塞,在知乎上看到了网友举的例子非常省动,在这里我引用下. 怎样理解阻塞非阻塞与同步异步的区别? 老张爱喝茶,废话不说,煮开水. 出场人物:老张,水壶两把(普通水壶,简称水壶:会响 ...
随机推荐
- 第36篇-return字节码指令
方法返回的字节码相关指令如下表所示. 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae freturn 从当前方法返回float 0xaf d ...
- HydroD:辅助脚本函数
HydroD:辅助函数 在HydroD中,使用JS脚本可以快速进行模拟参数设置,但是经过尝试,HydroD中的JS脚本语言并不支持现在JavaScript中的一些语法.所以考虑采用Matlab字符串拼 ...
- 端口被占用(启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099的解决办法)
一.问题描述 在IntelliJ IDEA 中启动Tomcat服务器时就出现了如下图所示的错误: 错误: 代理抛出异常错误**: java.rmi.server.ExportException: Po ...
- 第2章-6 求交错序列前N项和 (15分)
第2章-6 求交错序列前N项和 (15分) 本题要求编写程序,计算交错序列 1-2/3+3/5-4/7+5/9-6/11+- 的前N项之和. 输入格式: 输入在一行中给出一个正整数N. 输出格式: 在 ...
- 8大原则带你秒懂Happens-Before原则
摘要:在并发编程中,Happens-Before原则是我们必须要掌握的,今天我们就一起来详细聊聊并发编程中的Happens-Before原则. 本文分享自华为云社区<[高并发]一文秒懂Happe ...
- set比较大小
#include <iostream> using namespace std; #include <set> class Person{ public: Person(str ...
- 一个初步的lilypond模板
代码文档在下方,涉及了许多基本的文档操作,包括: 1)页面设置,包括纸张大小.页边距 2)段落设置,包括不同内容之间的行距 3)乐谱设置,包括设置谱子大小.谱号.调号.拍号,甚至还有拍号/小节线不可见 ...
- Python学习手册(第四版)——使用入门(自学用)
Python的优点 -可读性 -可移植性 -不是一个独立的工具,可以调用各种库,同时也可以被调用等等 -使编程变得很有趣 -面向对象 -可混合 Python的理念 随便找的一张图 脚本语言? Pyth ...
- 链式调用Builder
使用Lombok实现链式调用 1.静态调用 User对象: 对象中必须有一个值不为空staticname作为指定的参数并调用对象 @Accessors(chain = true) @Getter @S ...
- javascript-初级-day04js数据类型
day01-js数据类型 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type& ...