C# “为什么一个布尔”;旗;是否为异步/等待状态机生成?

C# “为什么一个布尔”;旗;是否为异步/等待状态机生成?,c#,async-await,compiler-generated,C#,Async Await,Compiler Generated,如果编译以下代码: private async Task<int> M() { return await Task.FromResult(0); } 在本例中,您将在启动第一个异步调用后的默认case语句中看到该变量的一个后续使用者: if (!awaiter.IsCompleted) { this.\u003C\u003E1__state = 0; this.\u003C\u003Eu__\u0024awaiter11 = awaiter; thi

如果编译以下代码:

private async Task<int> M()
{
    return await Task.FromResult(0);
}
在本例中,您将在启动第一个异步调用后的默认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;
}
如果(!waiter.IsCompleted)
{
此。\u003C\u003E1\uuuu状态=0;
这是。\u003C\u003Eu\u0024waiter11=等待者;
此。\u003C\u003Et\uuuu builder.AwaitUnsafeOnCompleted(ref waiter,ref this);
flag=false;
返回;
}
我尝试了六个比我最初的例子更复杂的例子,它们在退出方法之前只分配给这个变量是一致的。换句话说,在我到目前为止尝试过的所有情况下,这个变量不仅从未被使用过,而且在从方法返回之前,它只被赋予一个非初始值——在这个时间点,赋值在定义上是无用的

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


简而言之:为什么C#编译器会生成这个
标志
变量?

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


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

-伊莉安·平松

Stephen Cleary还为感兴趣的读者添加了一些有用的信息。他特别推荐


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


–Stephen Cleary

将等待语句包装在try finally块中,并在finally块中设置一些变量。我不完全理解IL逻辑在做什么,但我只是简单地看了一下,它似乎使用了那个标志变量来检查何时在finally块中执行代码。@IlianPinzon,我完全钦佩你的谦虚,但是如果你把这么好的回答作为答案,效果会更好。你完全正确,完全回答了我的问题@伊利安平松有正确的答案。这将在中进行更详细的解释。既然你在写交叉编译器,我强烈推荐。@Stephen,太好了,谢谢你的链接!
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;
}