总结起来,要想使一个方法可被 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. angular项目中ts的配置编译tsconfig.json

    { "compilerOptions": { /* 基本选项 */ "target": "es5", // 指定 ECMAScript 目标 ...

  2. Hadoop伪分布式重启正确流程

    既然是伪分布式,那就不可避免的设计到重启Hadoop服务或者重启Hadoop服务器的情况,正确的停止和重启是很有必要的. 首先是Hadoop服务的停止,使用 ./sbin/stop-all.sh脚本来 ...

  3. Python(os和sys)理解

    Python(os和sys)理解 os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口; sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时 ...

  4. Java操作FTP,从FTP上读取指定文件,把指定文件上传到FTP

    需要添加的依赖 <!-- https://mvnrepository.com/artifact/commons-net/commons-net --> <dependency> ...

  5. Linux下创建仓库的软件包createrepo

    createrepo是linux下的创建仓库的软件包.create是创建的意思,repo是repository的缩写,是仓库的意思. yum(Yellow dog Updater,Modified)主 ...

  6. 了解并安装Nginx

    公司使用nginx作为请求分发服务器,发现本人在查看nginx配置上存在些许困难,故仔细阅读了陶辉的<深入理解nginx模块开发与框架>第一部分,并作此记录. 了解 我根据书上的思路来了解 ...

  7. c++ 指定目录下的文件遍历

    要实现指定目录下文件的遍历需要执行一下的部分: 第一步获取当前路径的名字:(MAX_PATH是在windows定义的所有的路径名字不超过其,调用该函数会使得得到当前的目录) #include < ...

  8. kubernetes创建资源的两种方式

    一.创建方式分类: 命令 vs 配置文件 Kubernetes 支持两种方式创建资源: 1.用 kubectl 命令行的方式直接创建,比如: kubectl run httpd-app --image ...

  9. 在linux环境下安装oracle的问题记录

    问题1 xhost:unable to open display 解决办法: 在linux虚拟机本机打开终端,执行 [root@bogon ~]# DISPLAY=:0.0;export DISPLA ...

  10. solr创建core

    创建Core的两种方法: 第一种方法: 1.打开dos命令窗口,切换目录到${solr.home}\bin,然后输入:solr create -c corename之后回车: 2.打开solr安装文件 ...