简体   繁体   English

如果从 catch 块中抛出异常,什么时候最终运行?

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

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

In the above block when is the finally block called?在上面的块中,什么时候调用 finally 块? Before the throwing of e or is finally called and then catch?在抛出 e 之前或最终调用然后捕获?

It would be called after e is re-thrown (ie after the catch block is executed) 在重新抛出e之后(即在执行catch块之后)将调用它

editing this 7 years later - one important note is that if e is not caught by a try/catch block further up the call stack or handled by a global exception handler, then the finally block may never execute at all. 7年后编辑这个 - 一个重要的注意事项是,如果e未被调用堆栈进一步向上捕获或由全局异常处理程序处理,则finally可能永远不会执行。

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");
    }
}

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. 如果在catch块中重新抛出异常,并且该异常被捕获到另一个catch块内,则所有内容都根据文档执行。

  • However, if the re-trown exception is unhandled, the finally never executes. 但是,如果重新处理的异常未处理,则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: 示例1:重新抛出另一个try块:
--outer try - 外出尝试
----inner try ----内心尝试
----inner catch ----内心抓住
----inner finally ----内心终于
--outer catch - 外部捕获
--outer finally - 最后
Huzzah! 好哇!

Example 2: re-throw outside of another try block: 示例2:在另一个try块之外重新抛出:
--try - 尝试
--catch - 抓住

Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown. 未处理的异常:System.Exception:抛出了类型'System.Exception'的异常。
at ConsoleApplication1.Program.Main() in C:\\local source\\ConsoleApplication1\\Program.cs:line 53 在C:\\ local source \\ ConsoleApplication1 \\ Program.cs中的ConsoleApplication1.Program.Main()中:第53行

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; 作为旁注,如果你的意思是throw e; (that is, throw the same exception you just caught), it is much better to just do throw; (也就是你扔刚好赶上了同样的异常),它是好得多只是不throw; , since that will preserve the original stack trace instead of creating a new one. ,因为这将保留原始堆栈跟踪而不是创建新的跟踪。

If there is an unhandled exception inside a catch handler block, the finally block gets called exactly zero times 如果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 C:\\用户\\管理员\\文件\\ TestExceptionNesting \\ BIN \\发布> TestExceptionNesting.exe

in the try 在尝试

in the catch 在捕获

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero. 未处理的异常:System.DivideByZeroException:尝试除以零。 at TestExceptionNesting.Program.Main(String[] args) in C:\\users\\administrator\\documents\\TestExceptionNesting\\TestExceptionNesting.cs:line 22 在TestExceptionNesting.Program.Main(String [] args)中的C:\\ users \\ administrator \\ documents \\ TestExceptionNesting \\ TestExceptionNesting.cs:第22行

C:\\users\\administrator\\documents\\TestExceptionNesting\\bin\\release> C:\\用户\\管理员\\文件\\ TestExceptionNesting \\ BIN \\发布>

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. 我不确定这是否意味着一个技巧问题,或者面试官是否有其他想法,并为我编写了错误的代码进行调试,所以我回家试了一下(构建并运行,没有调试器交互),只是为了让我的想法休息。

一个简单的方法是调试代码并在最终调用时注意。

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. 使用C#控制台应用程序进行测试后,最终代码在抛出异常后执行:“应用程序错误对话框”已存在,在您选择“关闭程序”选项后,最终块在该控制台窗口中执行。 But setting the breaking point inside the finally code block, I can never hit it. 但是在最终代码块中设置断点,我永远不会打它。 The debugger keeps stopping at the throw statement. 调试器一直停在throw语句处。 Here is my test code: 这是我的测试代码:

    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

You can do it, I have done this to ensure cleanup.你可以做到,我这样做是为了确保清理。

using System;
class Program
{
static void Main()
{
    FinallyThrow();
    Console.ReadLine();
}
static void FinallyThrow()
{
    // Get finally block to execute EVEN IF there is an unhandled exception
    Exception thrownEx = null;
    try
    {
        Console.WriteLine("try..");
        throw new InvalidOperationException();
    }
    catch (Exception ex)
    {
        Console.WriteLine("catch..");
        thrownEx = ex;
    }
    finally
    {
        Console.WriteLine("finally..");
        if (thrownEx != null) throw thrownEx;
    }
}
}

OUTPUT (after breaking to the unhandled exception) OUTPUT(中断到未处理的异常后)

try..
catch..
finally..

. . Finally always run even if unhandled exception最终总是运行,即使未处理的异常

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM