最近在看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. cf17A Noldbach problem(额,,,素数,,,)

    题意: 判断从[2,N]中是否有超过[包括]K个数满足:等于一加两个相邻的素数. 思路: 枚举. 也可以:筛完素数,枚举素数,直到相邻素数和超过N.统计个数 代码: int n,k; int prim ...

  2. hdu 1166 敌兵布阵(简单线段树or树状数组)

    题意: N个工兵营地,第i个营地有ai个人. 三种操作: 1.第i个营地增加x个人. 2.第i个营地减少x个人. 3.查询第i个到第j个营地的总人数. 思路: 线段树or树状数组 代码:(树状数组) ...

  3. 《手把手教你》系列技巧篇(三十九)-java+ selenium自动化测试-JavaScript的调用执行-上篇(详解教程)

    1.简介 在做web自动化时,有些情况selenium的api无法完成,需要通过第三方手段比如js来完成实现,比如去改变某些元素对象的属性或者进行一些特殊的操作,本文将来讲解怎样来调用JavaScri ...

  4. 南大《软件分析》课程笔记——Data Flow Analysis

    南大<软件分析>--Data Flow Analysis @(静态分析) 目录 数据流分析概述 数据流分析应用 Reaching Definitions Analysis(may anal ...

  5. tmux会话断电保存自动恢复

    tmux可以用于会话管理,通过建立session,可以保证当前设备和服务期断开连接之后,会话中的指令继续运行,非常适合用于执行需要长时间运行的任务. 但是tmux也有一个问题,那就是session在服 ...

  6. CSS基础-行快属性,hover

    CSS基础 1.行快属性 在css中有很多标签,分为行内标签,块标签,标签行内块标签,他们有着不同的属性.     块标签         div,ul,li,ol,h1~h6,p         可 ...

  7. .net C# 释放内存 例子

    namespace myCommon{    public class SysVar    { [DllImport("kernel32.dll")]        public ...

  8. Django笔记&教程 3-2 模板语法介绍

    Django 自学笔记兼学习教程第3章第2节--模板语法介绍 点击查看教程总目录 参考:https://docs.djangoproject.com/en/2.2/topics/templates/# ...

  9. GO的安装以及GoLand破解

    GO的安装以及GoLand破解 GO的安装 GO语言中文网:GO语言中文网 go,GoLand,破解文件:JetBrains GoLand 2019.2.3 x64 提取码:ABCD(汉化文件也在其中 ...

  10. 设计模式学习-使用go实现模板模式

    模板模式 定义 模板模式的作用 优点 缺点 适用范围 代码实现 回调 模板模式 VS 回调 参考 模板模式 定义 模板模式(TemplateMethod):定义一个操作中的算法骨架,而将一些步骤延迟到 ...