最近在看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. 20191310李烨龙作业:MySort

    作业:MySort 任务详情 1. 用man sort 查看sort的帮助文档 2. sort常用选项有哪些,都有什么功能?提交相关使用的截图 3. 如果让你编写sort,你怎么实现?写出伪代码和相关 ...

  2. 基于 OSPF 路由的邻居邻接关系发现实践

    1.实验目的 理解 OSPF 邻居关系和 OSPF 邻接关系的含义及差别 观察 OSPF 邻居邻接关系的建立过程 观察 OSPF 链路状态数据库的同步过程 2.实验原理 OSPF 网络中,路由器在发送 ...

  3. 访问kubernetes CRD的几种方式

    访问kubernetes CRD的几种方式 最近在使用代码操作VictoriaMetrics Operator的CRD资源的过程中,探究了集中访问CRD资源的方式.下面以VictoriaMetrics ...

  4. PCB各层介绍

    在PCB设计中用得比较多的图层: mechanical 机械层 keepout layer 禁止布线层 Signal layer 信号层 Internal plane layer 内部电源/接地层 t ...

  5. SSH服务器拒绝了密码。请再试一次。怎么改都不行

    使用Xshell连接服务器,之前还好好的,突然之间就报"SSH服务器拒绝了密码.请再试一次"的错误. 1.检查 检查了IP.连接端口.用户.密码.网络是否正确? 本机情况:能够pi ...

  6. 第二课 Dubbo设计的架构设计

    总体架构 Dubbo的总体架构,如图所示: Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层.图中左边淡蓝背景的为 ...

  7. dart系列之:dart类中的泛型

    目录 简介 为什么要用泛型 怎么使用泛型 类型擦除 泛型的继承 泛型方法 总结 简介 熟悉JAVA的朋友可能知道,JAVA在8中引入了泛型的概念.什么是泛型呢?泛型就是一种通用的类型格式,一般用在集合 ...

  8. java web 在线编辑Excel -- x-spreadsheet

    --- x-spreadsheet --- 文档 https://hondrytravis.com/x-spreadsheet-doc/ <%@ page language="java ...

  9. R数据分析:跟随top期刊手把手教你做一个临床预测模型

    临床预测模型也是大家比较感兴趣的,今天就带着大家看一篇临床预测模型的文章,并且用一个例子给大家过一遍做法. 这篇文章来自护理领域顶级期刊的文章,文章名在下面 Ballesta-Castillejos ...

  10. CTF入门学习4->前端HTML基础

    Web安全基础 02 前端开发-HTML基础 浏览器对于上网者来说是一种直观.可视化的呈现.服务器发送数据到客户端,客户端需要处理这些数据,互联网就造就了这种数据语言--HTML. 02-00 概述 ...