总结起来,要想使一个方法可被 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

using System.Runtime.CompilerServices;

namespace Walterlv.Threading
{
/// <summary>
/// 表示一个可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待。
/// </summary>
/// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter 的实例。</typeparam>
public interface IAwaitable<out TAwaiter> where TAwaiter : IAwaiter
{
/// <summary>
/// 获取一个可用于 await 关键字异步等待的异步等待对象。
/// 此方法会被编译器自动调用。
/// </summary>
TAwaiter GetAwaiter();
} /// <summary>
/// 表示一个包含返回值的可等待对象,如果一个方法返回此类型的实例,则此方法可以使用 `await` 异步等待返回值。
/// </summary>
/// <typeparam name="TAwaiter">用于给 await 确定返回时机的 IAwaiter{<typeparamref name="TResult"/>} 的实例。</typeparam>
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
public interface IAwaitable<out TAwaiter, out TResult> where TAwaiter : IAwaiter<TResult>
{
/// <summary>
/// 获取一个可用于 await 关键字异步等待的异步等待对象。
/// 此方法会被编译器自动调用。
/// </summary>
TAwaiter GetAwaiter();
} /// <summary>
/// 用于给 await 确定异步返回的时机。
/// </summary>
public interface IAwaiter : INotifyCompletion
{
/// <summary>
/// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
/// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
/// </summary>
bool IsCompleted { get; } /// <summary>
/// 此方法会被编译器在 await 结束时自动调用以获取返回状态(包括异常)。
/// </summary>
void GetResult();
} /// <summary>
/// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
/// 用于给 await 确定异步返回的时机。
/// </summary>
public interface ICriticalAwaiter : IAwaiter, ICriticalNotifyCompletion
{
} /// <summary>
/// 用于给 await 确定异步返回的时机,并获取到返回值。
/// </summary>
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
public interface IAwaiter<out TResult> : INotifyCompletion
{
/// <summary>
/// 获取一个状态,该状态表示正在异步等待的操作已经完成(成功完成或发生了异常);此状态会被编译器自动调用。
/// 在实现中,为了达到各种效果,可以灵活应用其值:可以始终为 true,或者始终为 false。
/// </summary>
bool IsCompleted { get; } /// <summary>
/// 获取此异步等待操作的返回值,此方法会被编译器在 await 结束时自动调用以获取返回值(包括异常)。
/// </summary>
/// <returns>异步操作的返回值。</returns>
TResult GetResult();
} /// <summary>
/// 当执行关键代码(此代码中的错误可能给应用程序中的其他状态造成负面影响)时,
/// 用于给 await 确定异步返回的时机,并获取到返回值。
/// </summary>
/// <typeparam name="TResult">异步返回的返回值类型。</typeparam>
public interface ICriticalAwaiter<out TResult> : IAwaiter<TResult>, ICriticalNotifyCompletion
{
}
}

  

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

public class ContextAwaiter<T> : INotifyCompletion
{
readonly Control _control;
readonly TaskAwaiter<T> _awaiter;
readonly bool _alwaysAsync; public ContextAwaiter(Task<T> task, Control control, bool alwaysAsync)
{
_awaiter = task.GetAwaiter();
_control = control;
_alwaysAsync = alwaysAsync;
} public ContextAwaiter<T> GetAwaiter() { return this; } public bool IsCompleted { get { return !_alwaysAsync && _awaiter.IsCompleted; } } public void OnCompleted(Action continuation)
{
if (_alwaysAsync || _control.InvokeRequired)
{
Action<Action> callback = (c) => _awaiter.OnCompleted(c);
_control.BeginInvoke(callback, continuation);
}
else
_awaiter.OnCompleted(continuation);
} public T GetResult()
{
return _awaiter.GetResult();
}
}
}

  

实现一个可以用 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. TypeScript 和 JavaScript 的区别

    TypeScript 和 JavaScript 是目前项目开发中较为流行的两种脚本语言,我们已经熟知 TypeScript 是 JavaScript 的一个超集.JavaScript 和 TypeSc ...

  2. 写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印顺序为12A34B56C......5152Z

    题目: 写两个线程,一个线程打印1-52,另一个线程打印A-Z,打印顺序为12A34B56C......5152Z.要求用线程间的通信. /** * 写两个线程,第一个线程打印1-52,第二个线程打印 ...

  3. PPT中准确插入公式

    Mathtype直接输入到PPT中的公式,漂移且太小.一般的文本公式不美观. 将Mathtype的公式作为文本形式出现,既解决了漂移和大小的问题,也兼顾的美观. 具体操作如下: 1 打开Mathtyp ...

  4. 一文全面了解NB-IoT技术优势及特点

    1.NB-IOT多输入多输出技术 NB-IoT可以利用多天线技术抑制信道传输衰弱,获得分集增益.空间复用增益和阵列增益,在发送端和接收端均采用多天线实现信号同时发送和接收: 因此就形成了一个并行的多空 ...

  5. Ansible安装部署和常用命令,及其主机清单inventory(二)

    1.ansible的安装方式 1.1使用yum源安装 yum install ansible -y 1.2使用rpm包安装 https://dl.fedoraproject.org/pub/epel/ ...

  6. linux centos 7安装 apache php 及mariadb

    1安装Apache, PHP, MySQL以及php库组件. yum -y install httpd php mysql  php-mysql 2 安装apache扩展 yum -y install ...

  7. RPM包搭建

    打包rpm软件包之spec文件解析 1. 概述 RPM的全称是(Red Hat Package Manager,Red Hat包管理器).RPM是一个开放的软件包管理器,工作在Red Hat.类Lin ...

  8. Summer training round2 #7 (Training #23)

    A:约瑟夫环 套公式 B:线性筛素数 C:投骰子 概率DP F:有权无向图的生成树(边最大值和最小值只差最小) 直接kruskal G:状压BFS或者双向BFS H:模拟题 I:几何题 J:高斯消元

  9. 高性能mysql 第11章 可扩展的mysql

    可扩展性的定义:当增加资源以获得执行更多的工作系统能获得划算的同等提升. 向上扩展(垂直扩展):提升服务器的硬件性能. 向外扩展(水平扩展):一般都是复制,拆分,数据分片(sharding). 复制: ...

  10. 找到并更改启动时间(timeout)

    centos7更改引导项等待时间 centos7已经不用grub,改用grub2. [ root]# vi /boot/grub2/grub.cfg 找到并更改启动时间(timeout) [root] ...