草庐IT

c# - 在 try-finally block 中等待

coder 2023-07-13 原文

我一直在玩弄 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# - 在 try-finally block 中等待的更多相关文章

  1. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  2. ruby-on-rails - 更好的替代方法 try( :output). try( :data). try( :name)? - 2

    “输出”是一个序列化的OpenStruct。定义标题try(:output).try(:data).try(:title)结束什么会更好?:) 最佳答案 或者只是这样:deftitleoutput.data.titlerescuenilend 关于ruby-on-rails-更好的替代方法try(:output).try(:data).try(:name)?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.c

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  7. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  8. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  9. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

  10. c# - 先学什么? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭8年前。Improvethisquestion几年前我去学校学习编程,毕业后我找到了一份系统管理方面的工作,这就是我职业生涯的方向。我想重新开始某种开发,并且一直在“玩”C#和ASP.NET,但我已经听到很多关于其他"new"语言的讨论(新的意思是它们是新的)我)喜欢Ruby和F#。我想我想知道我是否在浪费时间学习主要的MS语言,而不是成为一名通才。很长一段时间没有离开开发社区(如果我曾经离开过的话)让我在潮流中挣扎,我不想落在时代的

随机推荐