为什么bool "标志"为async/await状态机生成的

本文关键字:quot 状态机 await bool 标志 为什么 async | 更新日期: 2023-09-27 17:50:02

如果编译以下代码:

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变量?

为什么bool "标志"为async/await状态机生成的

问题下面的评论描述了它的用法:

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

伊利安平邹

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

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

斯蒂芬·克利里