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

ror*_*.ap 7 .net c# task-parallel-library async-await ilspy

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

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

使用这种方法await Task.Delay(5000);,智能感知甚至说"(等待)":

在此输入图像描述

那怎么Task.Delay(int)没有标记async(public static async Task Delay(int millisecondsDelay))?

i3a*_*non 20

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

更一般地,每一件事,有一个GetAwaiter方法(扩展方法算好)返回的东西IsCompleted,OnCompleted并且GetResult可以期待的.

例如,Task.Yield返回YieldAwaitable不是a Task并且看起来像这样:

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

*UnsafeOnCompleted这里只是一个优化,await没有它就可以工作.

需要注意的是,在这种情况下,编译器(等同于在其他情况下,像很重要GetEnumeratorforeach)不期望的接口或基类.它基本上使用duck typing(即"如果它像鸭子一样行走......")并且只是寻找一个GetAwaiter返回任何东西的方法(无论是什么类型或接口,或者它是一个类还是一个结构) 3名成员(IsCompleted,OnCompletedGetResult)

例如,这是你如何进行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);
}
Run Code Online (Sandbox Code Playgroud)

总之,您不需要在.Net框架中async返回一个等待的,而且Task令人回味的方法,不要使用它并显式返回一个Task.