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

tga*_*ews 121 c#

try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}
Run Code Online (Sandbox Code Playgroud)

在上面的块中,finally块是什么时候调用的?在抛出e之前或者最后被召唤然后赶上?

Eri*_*lje 121

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

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

  • 如果你打电话给Envrionment.FailFast() (14认同)
  • 在Brandon的答案中尝试代码之后,我看到如果前面的`catch`中抛出的异常永远不会被*try` -`catch`块中的*捕获*,则不会执行`finally`! (12认同)
  • 感谢您编辑(已接受)答案以包含新信息. (3认同)
  • 他们(微软)在新的文档站点上讨论它:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally:"在一个已处理的异常中,最终关联保证阻止运行.但是,如果异常未处理,则finally块的执行取决于异常展开操作的触发方式.反过来,这取决于计算机的设置方式. (3认同)
  • 请注意,“由调用堆栈上方的 try/catch 块捕获”将包括框架处理程序,例如 ASP.NET 或测试运行程序中的框架处理程序。更好的表达方式可能是“如果程序在 catch 块之后继续运行,那么finally 块将执行”。 (2认同)

Mar*_*ell 81

为什么不尝试一下:

outer try
inner try
inner catch
inner finally
outer catch
outer finally
Run Code Online (Sandbox Code Playgroud)

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

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果你没有在外部捕获中捕获异​​常,内部最终永远不会执行!! 在这种情况下,输出是`外部尝试``内部尝试``内部catch``Unhandled Exception:System.DivideByZeroException ...` (7认同)
  • +1,对于这么简单的事情,你应该像Marc一样尝试它.GJ用嵌套的try/catch/finally来说明它:) (5认同)
  • @AllenRice 如果 Marc 已经有了,为什么要尝试它,我可以谷歌找到 Marc 的答案?或者也许更好,尝试自己,然后创建一个 SO 问题并为他人的利益自己回答。 (2认同)

Bra*_*on 32

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

  • 如果在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();
    }
Run Code Online (Sandbox Code Playgroud)

这是输出:

示例1:重新抛出另一个try块: -
asse try
---- inner try
---- inner catch
---- inner finally
--outer catch
--outer最后是
Huzzah!

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

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

  • 很棒,我没有意识到这一点! (3认同)
  • 有趣...在 .NET Core 2.0 上,finally 部分在未处理的异常之后运行。 (2认同)

Dan*_*den 23

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

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}
Run Code Online (Sandbox Code Playgroud)

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

  • 投掷+1; vs throw e;.这个概念错过了**很多**. (16认同)

小智 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");
     }
  }
Run Code Online (Sandbox Code Playgroud)

输出:

C:\用户\管理员\文件\ TestExceptionNesting\BIN \发布> TestExceptionNesting.exe

在尝试

在捕获

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

C:\用户\管理员\文件\ TestExceptionNesting\BIN \发布>

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