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

时间:2009-10-12 16:30:36

标签: c#

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

在上面的块中,finally块是什么时候调用的?在投掷e之前或最终被调用然后赶上?

7 个答案:

答案 0 :(得分:115)

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

7年之后编辑这个 - 一个重要的注意事项是,如果e没有被调试堆栈进一步向上调用或由全局异常处理程序处理,那么finally可能永远不会执行。

答案 1 :(得分:74)

为什么不尝试一下:

outer try
inner try
inner catch
inner finally
outer catch
outer finally
带代码的

(格式化为垂直空间):

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

答案 2 :(得分:30)

在阅读完这里的所有答案之后,看起来最终的答案是取决于

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

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

我在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();
    }

这是输出:

  

示例1:重新抛出另一个try块:
   - 外观尝试
  ----内心尝试   ----内部抓住   ----最终内心    - 外部捕获
   - 最后结局   好哇!

     

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

     

未处理的异常:System.Exception:类型的异常' System.Exception'扔了。
  在C:\ local source \ ConsoleApplication1 \ Program.cs中的ConsoleApplication1.Program.Main():第53行

答案 3 :(得分:23)

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

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

作为旁注,如果你的意思是throw e;(也就是说,抛出你刚刚抓到的同一个异常),那么只需{em> 就可以做throw;,因为这将保留原始堆栈跟踪而不是创建新的跟踪。

答案 4 :(得分:12)

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

输出:

  

C:\用户\管理员\文件\ TestExceptionNesting \ BIN \推出> TestExceptionNesting.exe

     尝试

中的

     

在捕获

     

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

     

C:\用户\管理员\文件\ TestExceptionNesting \ BIN \释放>

我今天在接受采访时被问到这个问题,面试官一直回过头来“你确定最终没有被召唤吗?”我不确定这是否意味着一个技巧问题,或者面试官是否有其他想法,并为我编写了错误的代码进行调试,所以我回家试了一下(构建并运行,没有调试器交互),只是为了让我的想法其余部分。

答案 5 :(得分:3)

一种简单的方法是调试代码并注意最终被调用。

答案 6 :(得分:1)

使用C#控制台应用程序进行测试,抛出异常后执行了最终代码:“应用程序错误对话框”已存在,在您选择“关闭程序”选项后,最终块在该控制台窗口中执行。 但是在最终代码块中设置断点,我永远不会打它。调试器一直停在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!");
         }

       }
    }

在VS2010中进行调试 - .NET Framework 4.0