C# 如果从 catch 块中抛出异常,finally 何时运行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1555567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 18:48:33  来源:igfitidea点击:

When is finally run if you throw an exception from the catch block?

c#

提问by tgandrews

try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}

In the above block when is the finally block called? Before the throwing of e or is finally called and then catch?

在上面的块中什么时候调用 finally 块?之前扔e还是最后调用然后catch?

采纳答案by Eric Petroelje

It would be called after e is re-thrown (i.e. after the catch block is executed)

将在重新抛出 e 后调用(即在执行 catch 块之后)

editing this 7 years later - one important note is that if eis not caught by a try/catch block further up the call stack or handled by a global exception handler, then the finallyblock maynever execute at all.

7 年后编辑它 - 一个重要的注意事项是,如果e没有被调用堆栈进一步向上的 try/catch 块捕获或由全局异常处理程序处理,则该finally可能永远不会执行。

回答by Daniel Pryden

Your example would behave identically to this code:

您的示例的行为与此代码相同:

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}

As a side note, if you really mean throw e;(that is, throw the same exception you just caught), it is muchbetter to just do throw;, since that will preserve the original stack trace instead of creating a new one.

作为一个侧面说明,如果你真正的意思throw e;(即扔你刚好赶上了同样的异常),它是好,只是这样做throw;,因为这将保留原始的堆栈跟踪,而不是创建一个新的。

回答by Marc Gravell

Why not try it:

为什么不试试:

outer try
inner try
inner catch
inner finally
outer catch
outer finally

with code (formatted for vertical space):

带代码(格式为垂直空间):

static void Main() {
    try {
        Console.WriteLine("outer try");
        DoIt();
    } catch {
        Console.WriteLine("outer catch");
        // swallow
    } finally {
        Console.WriteLine("outer finally");
    }
}
static void DoIt() {
    try {
        Console.WriteLine("inner try");
        int i = 0;
        Console.WriteLine(12 / i); // oops
    } catch (Exception e) {
        Console.WriteLine("inner catch");
        throw e; // or "throw", or "throw anything"
    } finally {
        Console.WriteLine("inner finally");
    }
}

回答by JonH

A simple way to tell also is to debug your code and notice when finally is called.

一种简单的判断方法是调试代码并注意 finally 何时被调用。

回答by Van Thi

Testing with a C# Console Application, the finally code has been executed after the exception is thrown: The "Application Error Dialog" existed and after you chose "Close the program" option, the finally block was executed in that console window. But setting the breaking point inside the finally code block, I can never hit it. The debugger keeps stopping at the throw statement. Here is my test code:

使用 C# 控制台应用程序进行测试,在抛出异常后执行了 finally 代码:存在“应用程序错误对话框”并且在您选择“关闭程序”选项后,在该控制台窗口中执行了 finally 块。但是在 finally 代码块内设置断点,我永远无法击中它。调试器一直停在 throw 语句处。这是我的测试代码:

    class Program
    {
       static void Main(string[] args)
       {
          string msg;
          Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
       }

       static int GetRandomNumber(out string errorMessage)
       {
         int result = 0;
         try
         {
            errorMessage = "";
            int test = 0;
            result = 3/test;
            return result;
         }
         catch (Exception ex)
         {
            errorMessage = ex.Message;
            throw ex;

         }
         finally
         {
            Console.WriteLine("finally block!");
         }

       }
    }

Debugging in VS2010 - .NET Framework 4.0

在 VS2010 中调试 - .NET Framework 4.0

回答by Eusebio Rufian-Zilbermann

If there is an unhandled exception inside a catch handler block, the finally block gets called exactly zerotimes

如果 catch 处理程序块中存在未处理的异常,则 finally 块将被精确调用

  static void Main(string[] args)
  {
     try
     {
        Console.WriteLine("in the try");
        int d = 0;
        int k = 0 / d;
     }
     catch (Exception e)
     {
        Console.WriteLine("in the catch");
        throw;
     }
     finally
     {
        Console.WriteLine("In the finally");
     }
  }

Output:

输出:

C:\users\administrator\documents\TestExceptionNesting\bin\Release>TestExceptionNesting.exe

in the try

in the catch

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero. at TestExceptionNesting.Program.Main(String[] args) in C:\users\administrator\documents\TestExceptionNesting\TestExceptionNesting.cs:line 22

C:\users\administrator\documents\TestExceptionNesting\bin\release>

C:\users\administrator\documents\TestExceptionNesting\bin\Release>TestExceptionNesting.exe

在尝试

在捕获

未处理的异常:System.DivideByZeroException:试图除以零。在 C:\users\administrator\documents\TestExceptionNesting\TestExceptionNesting.cs:line 22 中的 TestExceptionNesting.Program.Main(String[] args)

C:\users\administrator\documents\TestExceptionNesting\bin\release>

I got asked this question today at an interview and the interviewer kept going back "are you sure the finally doesn't get called?" I was uncertain if it was meant a trick question or the interviewer had something else in mind and wrote the wrong code for me to debug so I came home and tried it (build and run, no debugger interaction), just to put my mind at rest.

我今天在面试时被问到这个问题,面试官一直在说“你确定最后没有被叫到吗?” 我不确定这是否意味着一个棘手的问题,或者面试官有其他想法并为我编写了错误的代码来调试,所以我回家尝试了它(构建和运行,没有调试器交互),只是想把我的注意力放在休息。

回答by Brandon

After reading all of the answers here it looks like the final answer is it depends:

在阅读了此处的所有答案后,最终答案似乎取决于

  • If you re-throw an exception within the catch block, and that exception is caught inside of another catch block, everything executes according to the documentation.

  • However, if the re-trown exception is unhandled, the finally never executes.

  • 如果您在 catch 块内重新抛出异常,并且该异常在另一个 catch 块内被捕获,则一切都会根据文档执行。

  • 但是,如果重新生成的异常未处理,则 finally 永远不会执行。

I tested this code sample in VS2010 w/ C# 4.0

我在 VS2010 w/ C# 4.0 中测试了这个代码示例

static void Main()
    {
        Console.WriteLine("Example 1: re-throw inside of another try block:");

        try
        {
            Console.WriteLine("--outer try");
            try
            {
                Console.WriteLine("----inner try");
                throw new Exception();
            }
            catch
            {
                Console.WriteLine("----inner catch");
                throw;
            }
            finally
            {
                Console.WriteLine("----inner finally");
            }
        }
        catch
        {
            Console.WriteLine("--outer catch");
            // swallow
        }
        finally
        {
            Console.WriteLine("--outer finally");
        }
        Console.WriteLine("Huzzah!");

        Console.WriteLine();
        Console.WriteLine("Example 2: re-throw outside of another try block:");
        try
        {
            Console.WriteLine("--try");
            throw new Exception();
        }
        catch
        {
            Console.WriteLine("--catch");
            throw;
        }
        finally
        {
            Console.WriteLine("--finally");
        }

        Console.ReadLine();
    }

Here is the output:

这是输出:

Example 1: re-throw inside of another try block:
--outer try
----inner try
----inner catch
----inner finally
--outer catch
--outer finally
Huzzah!

Example 2: re-throw outside of another try block:
--try
--catch

Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown.
at ConsoleApplication1.Program.Main() in C:\local source\ConsoleApplication1\Program.cs:line 53

示例 1:在另一个 try 块内重新抛出:
--outer try
----inner try
----inner catch
----inner finally
--outer catch
--outer finally
哈扎哈!

示例 2:在另一个 try 块之外重新抛出:--
try
--catch

未处理的异常:System.Exception:抛出了“System.Exception”类型的异常。
在 C:\local source\ConsoleApplication1\Program.cs:line 53 中的 ConsoleApplication1.Program.Main()