如果编译以下代码:

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

然后反编译它(我使用dotpeek)并检查非常重要的MoveNext方法,您将看到一个bool变量在开头附近声明;dotpeek为我选择了“flag”。
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->js交叉编译器在javascript中实现async/await的过程。我想知道在什么情况下我需要考虑这个标志的效用。从表面上看,这似乎是假的,因此我应该忽略它。不过,我想知道为什么C编译器会引入这个变量——我怀疑有更复杂的表达式会以一种有用的方式使用这个变量。
简而言之:为什么C编译器生成这个flag变量?

最佳答案

在问题下面发表的以下评论描述了它的用途:
将await语句包装在try finally块中,并在finally块中设置一些变量。我不完全理解IL逻辑在做什么,但我只是做了一个快速的检查,它似乎使用那个标志变量来检查何时在finally块中执行代码。
——伊莉安·平松
斯蒂芬·克利里还为感兴趣的读者添加了一些有用的信息。他建议this blog series,特别是this blog post
@伊利安平宗的答案是正确的。这在jon skeet的eduaync文章中有更详细的解释。由于您正在编写一个交叉编译器,我强烈建议您阅读整个系列。
–斯蒂芬克利里

07-28 02:42
查看更多