C# 如果我从C中的try/finally块返回,finally中的代码是否总是运行?

C# 如果我从C中的try/finally块返回,finally中的代码是否总是运行?,c#,try-catch-finally,C#,Try Catch Finally,根据一些初始测试,它似乎是这样的,但我想知道的是,它是否保证返回或在某些情况下无法返回?这对我的应用程序至关重要,但我还没有找到一个不会返回的用例。 我想获得这方面的专业知识。在正常情况下,finally块中的代码将被执行,而不管try或catch块中发生了什么。不管您是否从该方法返回 有些情况下这是不正确的。例如,如果finally块中的代码抛出异常,那么它将像任何其他代码块一样停止执行 埃里克·利珀特(Eric Lippert)写了一个更全面的答案,概述了其他案例: 至于后藤,答案仍然是肯定

根据一些初始测试,它似乎是这样的,但我想知道的是,它是否保证返回或在某些情况下无法返回?这对我的应用程序至关重要,但我还没有找到一个不会返回的用例。

我想获得这方面的专业知识。

在正常情况下,finally块中的代码将被执行,而不管try或catch块中发生了什么。不管您是否从该方法返回

有些情况下这是不正确的。例如,如果finally块中的代码抛出异常,那么它将像任何其他代码块一样停止执行

埃里克·利珀特(Eric Lippert)写了一个更全面的答案,概述了其他案例:

至于后藤,答案仍然是肯定的。考虑下面的代码:

try
{
    Console.WriteLine("Inside the Try");
    goto MyLabel;
}
finally
{
    Console.WriteLine("Inside the Finally");
}

MyLabel:
    Console.WriteLine("After the Label");
产生的结果如下:

内部尝试

在最后

标签后面


在终止应用程序的致命异常情况下,将不调用最终块。包括堆栈溢出、要调用的方法的JIT期间的异常、ISDE CLR运行时的致命异常


正如@mintech所指出的,如果应用程序挂起在块内,它将无法到达finally块。这包括等待同步对象、死锁无限循环,甚至是无法关闭的UI。

其他答案中有许多不准确之处

当控件正常离开try块时,控件被传递到finally块——也就是说,通过返回、转到、中断、继续或从末尾掉下来。当控件通过已被封闭的catch块捕获的异常离开try块时,控件被传递到finally块

在任何其他情况下,都不能保证finally块中的代码会被调用。特别是:

  • 如果try块代码进入无限循环,或者线程被冻结且从未解冻,则永远不会调用finally块代码

  • 如果进程在调试器中暂停,然后主动终止,则永远不会调用finally块。如果进程没有快速失败,那么永远不会调用finally块

  • 如果将电源线从墙上拔出,则不会调用最后一个模块

  • 如果在没有相应catch块的情况下抛出异常,那么finally块是否运行是运行时的一个实现细节。当存在未捕获的异常时,运行时可以选择任何行为。“不运行finally块”和“运行finally块”都是“任何行为”的示例,因此可以选择其中一种。通常,运行时所做的是询问用户是否希望在运行finally块之前附加调试器;如果用户说不,那么finally块将运行。但是,同样地,运行时不需要这样做。它可能很快就会失败

您不能依赖始终调用finally块。如果您需要关于代码执行的有力保证,那么您不应该编写try finally,您应该编写try。正确编写CER是C#编程中最困难的任务之一,因此在编写代码之前,请仔细研究文档

顺便说一句,关于最终阻止gotos的一个“有趣的事实”是:

try { goto X; } finally { throw y; } 
X : Console.WriteLine("X");

X是一个不可到达的标签,目标是一个可到达的goto!所以下一次你在聚会上,你可以像“嘿,大家,有人能做一个C#程序,它有一个不可到达的标签,目标是一个可到达的goto吗?”然后你会看到聚会上谁读过可到达性规范,谁没有读过

以下是一些示例:

Environment.FailFast()

输出仅为“Try”

堆栈溢出

        try
        {
            Console.WriteLine("Try");
            Rec();
        }
        catch (Exception)
        {
            Console.WriteLine("catch");
        }
        finally
        {
            Console.WriteLine("finally");
        }
其中Rec为:

    private static void Rec()
    {
        Rec();
    }
输出仅为“Try”,进程因堆栈溢出而终止

未经处理的异常

        try
        {
            Console.WriteLine("Try");
            throw new Exception();
        }
        finally
        {
            Console.WriteLine("finally");
        }

有些异常不能像堆栈溢出一样被捕获。请参见:您能跳过您的场景吗?请记住,程序可以强制终止。从标题来看,您似乎在询问try{return;}finally{//mycode}是否将在finally中运行代码。答案是否定的。@DavidZ:事实上,答案是肯定的。可能的重复不仅回答了这个问题,还可能回答了OP以外的最隐含的问题。所以这个故事的寓意是:永远不要邀请Eric Lippert参加你的派对;)@Tergiver:鲜为人知的事实:编译器开发人员举办了最好的聚会。@qq:但这里有一个非常讨厌的聚会。假设您有
void X(){try{ObtainAdminPowers();DoSomethingDangerous();}最后{ReleaseAdminPowers();}}
DoSomethingDangerous
抛出异常。现在假设我们有
try{X();}catch(Exception)when(M()){}
。方法
M()
在释放管理员权限之前运行!
X
的作者相信,除了
dosomethingdangerious
之外,没有任何代码可以使用管理权限,但作者错了@在这种情况下,正确的缓解措施是荒谬的
void X(){try{get();DoIt();}catch{Release();throw;}Release();}
,这是任何明智的人都不会写的。这是.NET异常中的一个不幸的安全设计缺陷。@EricLippert可以说根本原因是
try{M}最后{N}
的含义不同于
{try{M}catch(Exception e){N;throw;}N}
。我理解其动机,但不禁想知道,如果不引入完全独立的异常相关原语,是否可以实现它。最后一个示例(未处理的异常)实际上执行
finally
块。
        try
        {
            Console.WriteLine("Try");
            throw new Exception();
        }
        finally
        {
            Console.WriteLine("finally");
        }