c# - 在 try-finally block 中等待

标签 c# compiler-construction async-await try-finally c#-6.0

我一直在玩弄 Visual Studio 14 CTP 2。此版本的 C# vNext 支持在 finally block 中使用 await 关键字。

我想弄清楚这是如何实现的。我知道这是一个实现细节,在 RTM 发布之前可能会发生变化,但我仍然需要针对此功能进行思考。

为了尝试理解底层编译器生成的代码,我创建了这个示例代码:

private async void button1_Click(object sender, EventArgs e)
{
    try
    {
    }
    finally
    {
        await MyFinallyTest();
    }
}

private async Task MyFinallyTest()
{
    await Task.Delay(1000);
}

这是编译器生成的类:

[CompilerGenerated]
private sealed class <button1_Click>d__1 : IAsyncStateMachine
{
    public int <>1__state;
    public Form1 <>4__this;
    public object <>7__wrap1;
    public int <>7__wrap2;
    public AsyncVoidMethodBuilder <>t__builder;
    public TaskAwaiter <>u__$awaiter0;

    private void MoveNext()
    {
        int num = this.<>1__state;
        try
        {
            TaskAwaiter awaiter;
            switch (num)
            {
                case 1:
                    break;

                default:
                {
                    this.<>7__wrap1 = null;
                    this.<>7__wrap2 = 0;

                    try
                    {
                    }
                    catch (object obj2)
                    {
                        this.<>7__wrap1 = obj2;
                    }

                    awaiter = this.<>4__this.MyFinallyTest().GetAwaiter();
                    if (awaiter.IsCompleted)
                    {
                        goto Label_0096;
                    }

                    this.<>1__state = num = 1;
                    this.<>u__$awaiter0 = awaiter;

                    Form1.<button1_Click>d__1 stateMachine = this;
                    this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, Form1.<button1_Click>d__1>(ref awaiter, ref stateMachine);
                    return;
                }
            }

            awaiter = this.<>u__$awaiter0;
            this.<>u__$awaiter0 = new TaskAwaiter();
            this.<>1__state = num = -1;

        Label_0096:
            awaiter.GetResult();
            awaiter = new TaskAwaiter();
            object obj3 = this.<>7__wrap1;
            if (obj3 != null)
            {
                Exception source = obj3 as Exception;
                if (source <= null)
                {
                    throw obj3;
                }
                ExceptionDispatchInfo.Capture(source).Throw();
            }

            int num1 = this.<>7__wrap2;
            this.<>7__wrap1 = null;
        }
        catch (Exception exception2)
        {
            this.<>1__state = -2;
            this.<>t__builder.SetException(exception2);
            return;
        }
        this.<>1__state = -2;
        this.<>t__builder.SetResult();
    }

    [DebuggerHidden]
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
    }
}

据我所知,编译器正在获取 finally 代码块并将其移动到编译器生成的 catch block 之后。如果我们想在 C# 6.0 之前 await 某些东西,我们必须做的事情类似于我们必须做的事情。

我看到一些我不明白的事情:

  1. 编译器正在添加生成的 catch block (这不是 以 catch (object obj2) 的形式出现在我的方法中)和 将其内部 object 设置为 obj2 异常。我不明白为什么要这样做。

  2. 我创建的finally block 不再存在。那是不是意味着 finally block 中的任何 awaited 代码都不会 开始“享受”我们从实际放置代码中获得的保证 在这样一个街区内?

最佳答案

编译器刚刚开始:

try
{
    Foo();
}
finally
{
    Bar();
}

变成类似的东西:

Exception caught = null;
try
{
    Foo();
}
catch (Exception e)
{
    caught = e;
}
Bar();
if (caught != null)
{
    throw caught;
}

...但以异步方式。它最终得到相同的结果 - 无论是否抛出异常,您的 finally block 仍将执行,它只是使用“捕获所有内容然后执行”而不是 finally< 的 IL 版本.

我建议您考虑在各种情况下执行流程会是什么样子(例如,是否在 try block 中抛出异常)并说服自己在每种情况下结果都是预期的。

关于为什么这不在 C# 5 中,Mads Torgersen 在 C# 6 CTP 文档中写道:

In C# 5.0 we don’t allow the await keyword in catch and finally blocks, because we'd somehow convinced ourselves that it wasn’t possible to implement. Now we've figured it out, so apparently it wasn't impossible after all.

关于c# - 在 try-finally block 中等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24867683/

相关文章:

c++ - 如何为我的自定义编译器制作解决方案资源管理器或项目界面

C# .NET 异步等待返回类型

javascript - mocha done() 和 async await 的矛盾问题

c# - asp.net 中的文件处理程序

compiler-construction - BISON + FLEX 语法 - 为什么标记被连接在一起

git 编译 : Documentation/git-add. xml 不验证

javascript - 等待结果的调用方法 - 中间值尚未解析

c# - 从 PropertyInfo[] 中删除属性

c# - task.Status == RanToCompletion 和 task.IsCompleted 的比较

c# - 接口(interface)在内部是如何工作的?