我们已经知道 Task 是可等待的,但是去看看 Task 类的实现,几乎找不到哪个基类、接口或者方法属性能够告诉我们与 await 相关。

而本文将探索什么样的类是可使用 await 异步等待的?


Dixin’s Blog - Understanding C# async / await (2) The Awaitable-Awaiter Pattern 一文解决了我们的疑惑。async/await 是给编译器用的,只要我们的类包含一个 GetAwaiter 方法,并返回合适的对象,我们就能让这个类的实例被 await 使用了。

既然需要一个 GetAwaiter 方法,那我们先随便写个方法探索一下:

Test DoAsync()
{
return new Test();
}
class Test
{
void GetAwaiter()
{
}
}

尝试调用:

await DoAsync();

编译器告诉我们:

Test.GetAwaiter() 不可访问,因为它具有一定的保护级别。

原来 GetAwaiter 方法需要是可以被调用方访问到的才行。

于是我们将 GetAwaiter 前面的访问修饰符改成 public。现在提示变成了:

await 要求类型 Test 包含适当的 GetAwaiter 方法。

考虑到一定要获取到某个对象才可能有用,于是我们返回一个 Test2 对象:

public class Test
{
public Test2 GetAwaiter()
{
return new Test2();
}
} public class Test2
{
}

这时编译器又告诉我们:

Test2 未包含 IsCompleted 的定义。

加上 public bool IsCompleted { get; },编译器又说:

Test2 不实现 INotifyCompletion。

于是我们实现之,编译器又告诉我们:

Test2 未包含 GetResult 的定义。

于是我们加上一个空的 GetResult 方法,现在编译器终于不报错了。

现在我们一开始的 DoAsync 和辅助类型变成了这样:

// 注:此处为试验代码。
private Test DoAsync()
{
return new Test();
} public class Test
{
public Test2 GetAwaiter()
{
return new Test2();
}
} public class Test2 : INotifyCompletion
{
public bool IsCompleted { get; }
public void GetResult() { }
public void OnCompleted(Action continuation) { }
}

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

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

更多编写自定义 Awaiter 的文章可以阅读:

入门篇:

实战篇:


参考资料

.NET 中什么样的类是可使用 await 异步等待的?的更多相关文章

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

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

  2. Java Native Interfce三在JNI中使用Java类的普通方法与变量

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 前面我们学习了如何在JNI中通过参数来使用J ...

  3. 换个新的思路 代替解压jar包 例证:wechat4j 框架中的templateMsg类

    很多朋友在写java的程序的时候都喜欢用第三方的jar包和框架,有可能遇到jar包中的内容已经跟不上官方开发者文档的更新,导致部分内容出错了,这个时候可能就要放弃这个jar的使用,但是这个jar中的其 ...

  4. 标准C++中的string类的用法总结

    标准C++中的string类的用法总结 相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有 ...

  5. 带有静态方法的类(java中的math类)

    带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...

  6. java-API中的常用类,新特性之-泛型,高级For循环,可变参数

    API中的常用类 System类System类包含一些有用的类字段和方法.它不能被实例化.属性和方法都是静态的. out,标准输出,默认打印在控制台上.通过和PrintStream打印流中的方法组合构 ...

  7. C++中如何定义类和对象?

    在C++语言中,对象的类型被称为类,类代表了某一批对象的共性和特征. 类是对象的抽象,而对象是类的具体实例.如同C中的结构体一样,我们要先定义一个结构体,再使用结构体去定义一个变量.同一个结构体可以定 ...

  8. Oracle数据库中调用Java类开发存储过程、函数的方法

    Oracle数据库中调用Java类开发存储过程.函数的方法 时间:2014年12月24日  浏览:5538次 oracle数据库的开发非常灵活,不仅支持最基本的SQL,而且还提供了独有的PL/SQL, ...

  9. 【转载】C++中的基类与派生类

    转自:http://www.cnblogs.com/sujz/articles/2044365.html 派生类的继承方式总结: 继承方式 说明 public 基类的public和protected的 ...

随机推荐

  1. Python - openpyxl 读写操作Excel

    openpyxl特点   openpyxl(可读写excel表)专门处理Excel2007及以上版本产生的xlsx文件,xls和xlsx之间转换容易 注意:如果文字编码是“gb2312” 读取后就会显 ...

  2. angular5表单验证问题

    例举一个patten的列子 可能出现的问题,表单元素需要添加name属性 还有的验证如maxlength,minlength,required等 一.验证某一个表单元素如下 *ngIf="s ...

  3. C#中的约束类型

  4. Java中泛型使用

    Java中泛型使用 泛型作用: 泛型:集合类添加对象不用强转 反射机制:将泛型固定的类的所有方法和成员全部显示出来 核心代码: ArrayList<Ls> ff=new ArrayList ...

  5. mRNA基本概念

    mRNA是由DNA的一条链转录而来的(可以是正链,也可以是反链),DNA是由非编码区和编码区组成,编码区也有其特殊的结构,主要有外显子和内含子组成. mRNA的一个重要性质就是可变剪切,也就是同一个编 ...

  6. Linux : 密码正确不能正常登陆,日志提示Could not get shadow information for user

    今天,再玩Centos7的时候,尝试修改了下ssh的端口.因为默认开启了SELinux,如果没有修改这个文件配置就修改端口sshd服务就不能正常启动了. 但是,当我修改会22端口的时候还是不能正常登陆 ...

  7. Codeword CodeForces - 666C (字符串计数)

    链接 大意:求只含小写字母, 长度为n, 且可以与给定模板串匹配的字符串个数 (多组数据) 记模板串为P, 长为x, 总串为S. 设$f_i$为S为i时的匹配数, 考虑P最后一位的首次匹配位置. 若为 ...

  8. Android将view保存为图片并放在相册中

    在Android中,可以将view保存为图片并放在相册中,步骤为 view->bitmap->file,即先将view转化为bitmap,再将bitmap保存到相册中. 需要将红框标注的v ...

  9. mysql 查询某一主键在那些表中中被设置为外键了

    use information_schema; show tables; select * from KEY_COLUMN_USAGE where COLUMN_NAME='areaid';

  10. PHP:第四章——数组中的排序函数

    <pre> <?php header("Content-Type:text/html;charset=utf-8"); //1) /*sort - 对数组进行升序 ...