如果没有标记为异步,Task.Delay是如何等待的?

我正在看Task.Delay(int)反编译的Task.Delay(int)

 // System.Threading.Tasks.Task [__DynamicallyInvokable] public static Task Delay(int millisecondsDelay) { return Task.Delay(millisecondsDelay, default(CancellationToken)); } 

使用此方法就像await Task.Delay(5000); ,intellisense甚至说“(等待)”:

在此处输入图像描述

那么如何将Task.Delay(int)标记为asyncpublic static async Task Delay(int millisecondsDelay) )?

什么是可以接受的Task Task.Delay返回。 返回Task / Task每个方法都是等待的。 async只是一个实现细节,允许您在该方法和它生成的整个状态机中使用await

更一般地说,每个具有GetAwaiter方法( 扩展方法都计数 )的东西都可以等待返回具有IsCompletedOnCompletedGetResult 东西

例如, Task.Yield返回的YieldAwaitable不是Task ,如下所示:

 public struct YieldAwaiter : ICriticalNotifyCompletion, INotifyCompletion { public void OnCompleted(Action continuation); public void UnsafeOnCompleted(Action continuation); public void GetResult(); public bool IsCompleted { get; } } 

*这里的UnsafeOnCompleted只是一个优化,没有它就await

重要的是要注意,在这种情况下编译器(与其他情况相同,如foreach GetEnumerator )不期望接口或基类。 它基本上使用duck typing (即“如果它像鸭子一样行走……” )并且只是寻找一个GetAwaiter方法,它返回任何类型或接口或者它是类或结构的任何东西(无关紧要)其他3个成员( IsCompletedOnCompletedGetResult

例如,这就是你可以await "bar"编译的方法(它当然会在运行时失败):

 public static Awaiter GetAwaiter(this string s) { throw new NotImplementedException(); } public abstract class Awaiter : INotifyCompletion { public abstract bool IsCompleted { get; } public abstract void GetResult(); public abstract void OnCompleted(Action continuation); } 

总之,您不需要async返回等待,而且.Net框架中的大多数Task返回方法不使用它并显式返回Task