为什么继续在GetResult()之前开始?

时间:2019-04-23 12:37:56

标签: c# async-await

class MyAwaitable
{
    public MyAwaiter GetAwaiter()
    {
        return new MyAwaiter();
    }
    public class MyAwaiter : INotifyCompletion
    {
        public bool IsCompleted { get; }
        public void GetResult()
        {
            Console.WriteLine("GetResult().");
        }
        public void OnCompleted(Action continuation)
        {
            Console.WriteLine("Continuation begins.");
            continuation();
            Console.WriteLine("Continuation ends.");
        }
    }
}



class Program
{
    static async Task Main()
    {
        await new MyAwaitable();
        Console.WriteLine("The last code.");
    }
}

输出:

  

继续开始。

     

GetResult()。

     

最后一个代码。

     

继续结束。

问题

我真的不明白为什么Continuation begins.GetResult().之前出现。根据我的直觉,GetResult()应该排在第一位。

为什么继续在GetResult()之前开始?

1 个答案:

答案 0 :(得分:1)

continuation是在等待的事物完成时执行的委托。通常,正在等待的TaskAwaiter会将continuation存储在一个字段中,并在Task完成时运行它。

由编译器生成的状态机使用该状态机前进到下一个状态,该状态又将在等待的事物上调用.GetResult()(都将得到结果,并抛出任何异常);

因此continuation是一个委托人,最终调用了GetResult()

您可以找到OnCompleted被称为here的位置。 continuationAsyncMethodBuilderCore.GetCompletionActionMoveNextRunner.Runcalls MoveNext on the state machine创建它的结果。

如果您查看compiler-generated code for your async method,可以看到MoveNext呼叫awaiter.GetResult()

要了解Task在这里的工作方式,请从TaskAwaiter.OnCompleted开始,并看到它调用了Task.SetContinuationForAwait,后者调用了AddTaskContinuation,最终将其存储在{{3 }}。然后在m_continuationObject中调用它。