【问题标题】:Why does a bool "flag" get generated for the async/await state machine?为什么会为 async/await 状态机生成布尔“标志”?
【发布时间】:2014-04-17 15:35:24
【问题描述】:

如果编译如下代码:

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

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

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 块中执行代码。
  • @IlianPinzon,我非常钦佩您的谦虚,但是如果您发布如此出色的回复作为答案,SO 效果会更好。您是绝对正确的,并且完美地回答了我的问题。 :)
  • @IlianPinzon 有正确答案。这在one of Jon Skeet's eduasync posts 中有更详细的解释。由于您正在编写交叉编译器,我强烈推荐reading that whole series
  • @Stephen,太好了,感谢您的链接!

标签: c# async-await compiler-generated


【解决方案1】:

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

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

——伊利安·平松

Stephen Cleary 还为感兴趣的读者添加了一些有用的信息。他推荐this blog series,尤其是this blog post

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

——斯蒂芬·克利里

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-24
    • 2017-10-26
    • 2021-10-09
    • 2016-10-06
    相关资源
    最近更新 更多