总结起来,要想使一个方法可被 await 等待,必须具备以下条件:

这个方法返回一个类 A 的实例,这个类 A 必须满足后面的条件。
此类 A 有一个可被访问到的 GetAwaiter 方法(扩展方法也行,这算是黑科技吗?),方法返回类 B 的实例,这个类 B 必须满足后面的条件;
此类 B 实现 INotifyCompletion 接口,且拥有 bool IsCompleted { get; } 属性、GetResult() 方法、void OnCompleted(Action continuation) 方法。
https://blog.csdn.net/WPwalter/article/details/78387736

  1. using System.Runtime.CompilerServices;
  2.  
  3. namespace Walterlv.Threading
  4. {
  5. /// <summary>
  6. /// 表示一个可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待。
  7. /// </summary>
  8. /// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter 的实例。</typeparam>
  9. public interface IAwaitable<out TAwaiter> where TAwaiter : IAwaiter
  10. {
  11. /// <summary>
  12. /// 获取一个可用于 await 关键字异步等待的异步等待对象。
  13. /// 此方法会被编译器自动调用。
  14. /// </summary>
  15. TAwaiter GetAwaiter();
  16. }
  17.  
  18. /// <summary>
  19. /// 表示一个包含返回值的可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待返回值。
  20. /// </summary>
  21. /// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter{<typeparamref name="TResult"/>} 的实例。</typeparam>
  22. /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
  23. public interface IAwaitable<out TAwaiter, out TResult> where TAwaiter : IAwaiter<TResult>
  24. {
  25. /// <summary>
  26. /// 获取一个可用于 await 关键字异步等待的异步等待对象。
  27. /// 此方法会被编译器自动调用。
  28. /// </summary>
  29. TAwaiter GetAwaiter();
  30. }
  31.  
  32. /// <summary>
  33. /// 用于给 await 确定异步返回的时机。
  34. /// </summary>
  35. public interface IAwaiter : INotifyCompletion
  36. {
  37. /// <summary>
  38. /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
  39. /// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
  40. /// </summary>
  41. bool IsCompleted { get; }
  42.  
  43. /// <summary>
  44. /// 此方法会被编译器在 await 结束时自动调用以获取返回状态(包括异常)。
  45. /// </summary>
  46. void GetResult();
  47. }
  48.  
  49. /// <summary>
  50. /// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
  51. /// 用于给 await 确定异步返回的时机。
  52. /// </summary>
  53. public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion
  54. {
  55. }
  56.  
  57. /// <summary>
  58. /// 用于给 await 确定异步返回的时机,并获取到返回值。
  59. /// </summary>
  60. /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
  61. public interface IAwaiter<out TResult> : INotifyCompletion
  62. {
  63. /// <summary>
  64. /// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
  65. /// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
  66. /// </summary>
  67. bool IsCompleted { get; }
  68.  
  69. /// <summary>
  70. /// 获取此异步等待操作的返回值,此方法会被编译器在 await 结束时自动调用以获取返回值(包括异常)。
  71. /// </summary>
  72. /// <returns>异步操作的返回值。</returns>
  73. TResult GetResult();
  74. }
  75.  
  76. /// <summary>
  77. /// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
  78. /// 用于给 await 确定异步返回的时机,并获取到返回值。
  79. /// </summary>
  80. /// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
  81. public interface ICriticalAwaiter<out TResult> : IAwaiter<TResult>, ICriticalNotifyCompletion
  82. {
  83. }
  84. }

  

https://stackoverflow.com/questions/19535147/await-and-synchronizationcontext-in-a-managed-component-hosted-by-an-unmanaged-a/19555959#19555959

  1. public class ContextAwaiter<T> : INotifyCompletion
  2. {
  3. readonly Control _control;
  4. readonly TaskAwaiter<T> _awaiter;
  5. readonly bool _alwaysAsync;
  6.  
  7. public ContextAwaiter(Task<T> task, Control control, bool alwaysAsync)
  8. {
  9. _awaiter = task.GetAwaiter();
  10. _control = control;
  11. _alwaysAsync = alwaysAsync;
  12. }
  13.  
  14. public ContextAwaiter<T> GetAwaiter() { return this; }
  15.  
  16. public bool IsCompleted { get { return !_alwaysAsync && _awaiter.IsCompleted; } }
  17.  
  18. public void OnCompleted(Action continuation)
  19. {
  20. if (_alwaysAsync || _control.InvokeRequired)
  21. {
  22. Action<Action> callback = (c) => _awaiter.OnCompleted(c);
  23. _control.BeginInvoke(callback, continuation);
  24. }
  25. else
  26. _awaiter.OnCompleted(continuation);
  27. }
  28.  
  29. public T GetResult()
  30. {
  31. return _awaiter.GetResult();
  32. }
  33. }
  34. }

  

实现一个可以用 await 异步等待的 Awaiter的更多相关文章

  1. 如何实现一个可以用 await 异步等待的 Awaiter

    .NET 和 C# 共同给我们带来的 async/await 异步编程模型(TAP)用起来真的很爽.为了实现异步等待,我们只需要在一切能够能够异步等待的方法前面加上 await 即可.能够异步等待的最 ...

  2. .NET 中什么样的类是可使用 await 异步等待的?

    我们已经知道 Task 是可等待的,但是去看看 Task 类的实现,几乎找不到哪个基类.接口或者方法属性能够告诉我们与 await 相关. 而本文将探索什么样的类是可使用 await 异步等待的? D ...

  3. .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter

    林德熙 小伙伴希望保存一个文件,并且希望如果出错了也要不断地重试.然而我认为如果一直错误则应该对外抛出异常让调用者知道为什么会一直错误. 这似乎是一个矛盾的要求.然而最终我想到了一个办法:让重试一直进 ...

  4. 定义一组抽象的 Awaiter 的实现接口,你下次写自己的 await 可等待对象时将更加方便

    我在几篇文章中都说到了在 .NET 中自己实现 Awaiter 情况.async / await 写异步代码用起来真的很爽,就像写同步一样.然而实现 Awaiter 没有现成的接口,它需要你按照编译器 ...

  5. 将 async/await 异步代码转换为安全的不会死锁的同步代码

    在 async/await 异步模型(即 TAP Task-based Asynchronous Pattern)出现以前,有大量的同步代码存在于代码库中,以至于这些代码全部迁移到 async/awa ...

  6. c# async/await异步编程死锁的问题

    在异步编程中,如果稍有不注意,就会造成死锁问题.何为死锁:即两个以上的线程同时争夺被互相锁住的资源,两个都不放手. 在UI或asp.net中,容易造成死锁的代码如下所示: private void b ...

  7. Async and Await 异步和等待

    [第一次这么耐下性子认真写博客,虽然觉得很认真了,当毕竟是第一次嘛,以后再看肯定觉得很不咋滴的,更何况园子里有那么多的高人和大侠,这篇文章就权当练练手了,熟悉一下用客户端发表博客了,也希望大家多多照顾 ...

  8. Async和Await异步编程的原理

    1. 简介 从4.0版本开始.NET引入并行编程库,用户能够通过这个库快捷的开发并行计算和并行任务处理的程序.在4.5版本中.NET又引入了Async和Await两个新的关键字,在语言层面对并行编程给 ...

  9. async And await异步编程活用基础

    原文:async And await异步编程活用基础 好久没写博客了,时隔5个月,奉上一篇精心准备的文章,希望大家能有所收获,对async 和 await 的理解有更深一层的理解. async 和 a ...

随机推荐

  1. linux CUDA安装

    首先是安装依赖库 sudo apt-get install freeglut3-dev build-essential libx11-dev libxmu-dev libxi-dev libgl1-m ...

  2. 多线程编程-- part5.1 互斥锁之公平锁-释放锁

    释放公平锁 1.unlock() unlock()在ReentrantLock.java中实现的,源码如下: public void unlock() { sync.release(1); } 说明: ...

  3. 89. Gray Code (Java)

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...

  4. 微信小程序获得高度

    wx.getSystemInfo({ success: (res) => { wx.createSelectorQuery().select('#scrollbox').boundingClie ...

  5. 运行期优化 Java内存模型与线程 线程安全与优化

  6. linux命令详解——ftp

    ftp服务器在网上较为常见,Linux ftp命令的功能是用命令的方式来控制在本地机和远程机之间传送文件,这里详细介绍Linux ftp命令的一些经常使用的命令,相信掌握了这些使用Linux 进行ft ...

  7. shell 实用脚本2

    脚本功能 拷贝文件夹 及 子文件夹内文件  到 对应的 文件结构下 ,且拷贝前先进行备份 #!/bin/sh #create by lizr -- #脚本功能 #覆盖文件前先备份 cfsuffix=$ ...

  8. nginx 常用的命令和配置文件

    常用的命令 进入 nginx 目录中 cd  /usr/local/nginx/sbin 1.查看 nginx 版本号  ./nginx -v  2.启动 nginx  ./nginx  3.停止 n ...

  9. python进阶ing——创建第一个Tornado应用

    python进阶ing——创建第一个Tornado应用 分类: Python2013-06-02 23:02 1725人阅读 评论(2) 收藏 举报 pythonTornado 每天在群里跟很多群友讨 ...

  10. Attention机制中权重的计算

    Attention mechanism中,给输入序列中对应的每一个Ht分配权重(打分)究竟是如何打分? 输入序列打分,a(s, h) 其中s是输出序列的t-1时刻的隐藏层状态,h是输入的多个状态,