4
try
{
    try
    {
        throw new Exception("From Try");
    }
    catch
    {
        throw new Exception("From Catch");
    }
    finally
    {
        throw new Exception("From Finally");
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

上面代码的输出是:From Finally.

为什么不是From Catch

-或者-

我如何从两个异常之外捕获和记录?

4

8 回答 8

6

因为 finally 块在 catch 块之后执行,覆盖了异常。

并且当在处理较早的异常时发生异常时,第一个异常会丢失。

我如何从两个异常之外捕获和记录?

  1. 通过扔在 finally 块内。这总是一个坏主意。
  2. 如果要登录内部 catch 块,请使用throw;或将第一个异常作为新异常的 InnerException 传递。这就是InnerException 存在的原因。
于 2010-09-29T22:35:15.917 回答
3

这是 C# 语言规范定义的行为。块内抛出的异常的处理try被中止,而是finally将处理块内抛出的异常。

相关的第8.9.5 节 throw 语句解释了异常是如何传播的:

  • 在当前函数成员中,try检查包含抛出点的每个语句。对于每个语句S,从最里面的try语句开始,到最外面的try语句结束,评估以下步骤:

    • 如果 try 块S包含抛出点并且 ifS有一个或多个catch子句,则catch按照出现的顺序检查这些子句以找到适合异常的处理程序。catch指定异常类型或异常类型的基类型的第一个子句被视为匹配项。一般catch子句 ( §8.10) 被认为是任何异常类型的匹配项。如果找到匹配的catch子句,则通过将控制转移到该catch子句的块来完成异常传播。

    • 否则,如果try块或catchS包围了抛出点并且如果S有一个finally块,则控制转移到finally块。如果finally块抛出另一个异常,则终止当前异常的处理。否则,当控制到达块的终点时,finally继续当前异常的处理。

于 2010-09-29T22:49:53.053 回答
1

添加一层额外的 try-catch 块,如下所示:

try {
    Exception fromCatch = null;
    try {
        throw new Exception("From Try");
    }
    catch {
        try {
            throw new Exception("From Catch");
        }
        catch (Exception e) {
            // catch failed -> store exception
            fromCatch = e;
        }
    }
    finally {
        try {
            throw new Exception("From Finally");
        }
        catch (Exception e) {
            // i can think of better exception merging... but this shows the idea
            throw new Exception(e.Message, fromCatch);
        }
        // throw fromCatch, in case "From Finally did not happen"
        throw fromCatch;
    }
}
catch (Exception ex) {
    Console.WriteLine(ex.Message);
    if (ex.InnerException != null) {
        Console.WriteLine(ex.InnerException.Message);
    }
}

报告:

From Finally
From Catch

编辑:这显然是问题二的答案,因为“为什么”得到了充分的回答:)

于 2010-09-29T23:41:08.223 回答
0

最后总是运行;它总是最后运行。所以内部 try 完成的 lat 事情是 finally 并且抛出了被外部 catch 捕获的东西

不确定我是否理解问题的第 2 部分

于 2010-09-29T22:33:50.723 回答
0

finally无论如何都会发生。不管try还是catch中是否有异常。因此,您会看到“From Final”。(这实际上是该子句的全部目的finally。因此,您可以将代码放在那里,无论如何都会清理资源等 - 即使有异常。)

于 2010-09-29T22:34:25.900 回答
0

您的代码从 try/catch/finally 语句的每个部分抛出一个新异常。当您创建新错误时,您实际上是在吞噬先前的异常。您可以将“From Try”消息添加到“From Catch”消息中,例如

catch(Exception ex)
{
    throw new Exception(ex.Message + ":" + "From Catch");
}

我不知道你怎么能把它锁在最后。

于 2010-09-29T22:45:16.070 回答
0

因为 finally 块总是被执行。

try 
{ 
    try 
    { 
        throw new Exception("From Try"); 
        // (1) A new exception object A is created here and thrown.
    } 
    catch // (2) Exception object A is catched.
    { 
        throw new Exception("From Catch"); 
        // (3) A new exception object B is created here and thrown.
    } 
    finally // (4) Execution is forced to continue here!
    { 
        throw new Exception("From Finally"); 
        // (5) A new exception object C is created here and thrown.
    } 
} 
catch (Exception ex) // (6) Exception object C is catched.
{ 
    Console.WriteLine(ex.Message); 
} 

步骤 (3) 和 (5) 中的每个新异常对象都会丢弃前一个异常对象。由于始终执行 finally 块,因此剩下的就是步骤 (5) 中的异常对象 C。

于 2010-09-29T22:46:56.160 回答
0

这是一个很好的问题,而且有点棘手。让我们一步一步来:

try
{
    throw new Exception("From Try");
}
catch
{
    throw new Exception("From Catch");
}

在上面的代码中,Exception("From Try")被 catch 子句抛出并捕获(到目前为止非常简单)。catch 子句抛出它自己的异常,通常我们希望(因为 catch 嵌套在更大的 try-catch 块中)会立即被捕获,但是......

finally
{
   throw new Exception("From Finally");
}

finally 子句保证(尝试)执行,它首先出现,并抛出它自己的异常,覆盖之前抛出的Exception("From Catch")

“catch 和 finally 一起的一个常见用法是在 try 块中获取和使用资源,在 catch 块中处理异常情况,并在 finally 块中释放资源” - MSDN 文章

按照这一系列逻辑,我们应该尽量避免在我们的 catch 和 finally 块中编写容易发生异常的代码。如果您担心出现您提出的那种情况,我建议您将异常及其相关信息记录到外部文件中,您可以参考该文件进行调试。

于 2010-09-29T23:02:48.407 回答