本文告诉大家 await 的高级用法,包括底层原理。
昨天看到太子写了一段代码,我开始觉得他修改了编译器,要不然下面的代码怎么可以编译通过
await "林德熙逗比";
需要知道,基本可以添加 await 都是可以等待的类型,如 Task 。如果一个类需要可以被等待,那么这个类必须满足以下条件
-
类里有一个 GetAwaiter 函数
-
GetAwaiter 有返回值,返回值需要继承 INotifyCompletion 并且有
bool IsCompleted { get; }
,GetResult()
,void OnCompleted(Action continuation)
定义
参见:如何实现一个可以用 await 异步等待的 Awaiter - walterlv
但是上面的代码使用的是一个字符串,什么时候可以修改继承字符串?
先让我来说下 await 原理,因为知道了原理,上面的代码实现很简单。看完了本文,你就会知道如何让几乎所有类型包括 int 、string 、自定义的类都支持 await 。
如果真的不想看原理,那么请直接调到文章的最后,看到最后很快就知道如何做。
原理
在 .net 4.5 之后,框架默认提供 async 和 await 的语法糖,这时千万不要认为进入 await 就会进入一个新的线程,实际上不一定会进入一个新的线程才会调用 await 。
那么 await 的语法糖写的是什么?实际上就是以前的 Begin xx 和 End xx 的语法糖。
古时候的写法:
foo.Beginxx();
foo.Endxx(传入委托);
这样大家就无法在一个流程写完,需要分为两个东西,而在 Continus with 下,就需要传入委托。如果委托里又使用了异步,那么又需要传入委托
task.ContinueWith(_ =>
{
Task t1 = new Task(() => {
});
t1.ContinueWith((t2) =>
{
//可以看到如果进入很多的委托
});
});
所以这时就使用了 await ,可以让大家按照顺序写。
await task;
Task t1 = new Task(() => {
});
await t1;
//可以看到这时不需要进入委托
实际上 await 是在编译时支持的,请看进阶篇:以IL为剑,直指async/await - 布鲁克石 - 博客园
而且千万不要认为 await 一定会进入一个新的线程,实际上他只是把需要写在多处的代码,可以按照流写下载,和写同步代码一样。如果感兴趣 await 不一定会进入一个新的线程请看 There Is No Thread
使用
因为 await 需要找到一个 GetAwaiter 函数,这个函数即使是扩展方法也可以,所以其实上面的代码是这样写的
public static class KvpbamjhKsvm
{
public static HeabdsdnbKevx GetAwaiter(this string str)
{