为什么为async / await状态机生成bool“flag”?

时间:2014-03-13 05:07:02

标签: c# async-await compiler-generated

如果您编译以下代码:

private async Task<int> M()
{
    return await Task.FromResult(0);
}

然后反编译它(我使用dotPeek)并检查最重要的MoveNext方法,你会看到在开头附近声明了一个bool变量; dotPeek选择&#34; flag&#34;对我来说。

bool flag = true;

在这种情况下,您将在启动第一个异步调用后的默认case语句中看到该变量的后续使用者:

if (!awaiter.IsCompleted)
{
    this.\u003C\u003E1__state = 0;
    this.\u003C\u003Eu__\u0024awaiter11 = awaiter;
    this.\u003C\u003Et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<int>, Program.\u003CP\u003Ed__10>(ref awaiter, ref this);
    flag = false;
    return;
}

我已经尝试了比初始版本更复杂的示例六个,并且在退出方法之前,仅分配给此变量是一致的。换句话说,在我迄今为止尝试过的所有情况中,这个变量不仅从不消耗,而且只是在从方法返回之前立即给出非初始值 - 分配的时间点在定义上是无用的。

作为背景,我很享受尝试通过C#在Javascript中实现异步/等待的过程 - &gt; JS交叉编译器。我试图了解在什么情况下我需要考虑这个标志的效用。面对面,它似乎是虚假的,因此我应该忽略它。但是,我想了解为什么C#编译器引入了这个变量 - 我怀疑有更复杂的表达式以有用的方式使用这个变量。

简洁地说:为什么C#编译器生成这个flag变量?

1 个答案:

答案 0 :(得分:1)

在该问题下发布的以下评论描述了其用途:

  

将await语句包装在try-finally块中,并在finally块中设置一些变量。我不完全理解IL逻辑正在做什么,但我只是快速查看它看起来像使用该标志变量来检查何时执行finally块内的代码。

-Ilian Pinzon

Stephen Cleary也为感兴趣的读者添加了一些有用的信息。他建议this blog series,特别是this blog post

  

@IlianPinzon有正确的答案。 Jon Skeet的一个eduasync帖子更详细地解释了这一点。由于您正在编写交叉编译器,我强烈建议您阅读整个系列。

-Stephen Cleary