总结起来,要想使一个方法可被 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. python 短信邮件

    短信邮件 hashlib​- md5:非对称加密,不可逆的,经常用于加密密码然后存储​- 示例:​ ```python import hashlib ​ # 创建hash对象,可以指定需要加密的字符串 ...

  2. docker中centos7安装ssh服务

    来源:https://blog.csdn.net/qq_32969313/article/details/64919735 docker安装好后,自己动手做个自己的docker镜像,首先需要从服务器p ...

  3. Golang中的匿名函数(闭包)

    GO语言的匿名函数就是闭包,以下是<GO语言编程>中对闭包的解释 基本概念闭包是可以包含自由(未绑定到特定对象)变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代 ...

  4. zabbix 性能优化

    Zabbix 安装好就放在那不管了,以为不需要调优.直到最近出现了如下一堆告警. 描述下我们的环境 硬件:8核 32G 软件:Centos7.6 Zabbix4.0.Httpd2.4.PHP7.3.M ...

  5. SQL SERVER 查询被锁的表、解锁表

    -- 查询被锁的表select   request_session_id   spid,OBJECT_NAME(resource_associated_entity_id) tableName   f ...

  6. java执行字符串中的运算公式

    import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.Scrip ...

  7. 14Filter&Listener

    1.Filter:过滤器 1.1 概念 生活中的过滤器:净水器,空气净化器,土匪. web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能. 过滤器的作用: 一般用于完成 ...

  8. 背包 || NOIP 2018 D1 T2 || Luogu P5020 货币系统

    题面:P5020 货币系统 题解: 显然要求的货币系统是当前货币系统的子集时答案会更优,于是考虑从当前货币系统中删数 一个大数如果能被其他小数表示出来,它就可以去掉 把数据排个序去个重,然后直接背包 ...

  9. Python核心技术与实战——二十|assert的合理利用

    我们平时在看代码的时候,或多或少会看到过assert的存在,并且在有些code review也可以通过增加assert来使代码更加健壮.但是即便如此,assert还是很容易被人忽略,可是这个很不起眼的 ...

  10. jenkins之Extended Choice Parameter多选插件