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

Kir*_*oll 11 c# async-await compiler-generated

如果您编译以下代码:

private async Task<int> M()
{
    return await Task.FromResult(0);
}
Run Code Online (Sandbox Code Playgroud)

然后反编译它(我使用dotPeek)并检查所有重要的MoveNext方法,你会看到一个bool在开头附近声明的变量; dotPeek为我选择了"旗帜".

bool flag = true;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将在启动第一个异步调用后的默认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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

简单来说:为什么C#编译器会生成这个flag变量?

fli*_*erg 1

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

\n\n
\n

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

\n
\n\n

\xe2\x80\x93伊利安·平松

\n\n

Stephen Cleary 还为感兴趣的读者添加了一些有用的信息。他推荐这个博客系列,特别是这篇博客文章

\n\n
\n

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

\n
\n\n

\xe2\x80\x93斯蒂芬·克利里

\n