7

可能重复:
为什么在 C# 中捕获并重新抛出异常?

我有时会遇到如下所示的 C# 代码:

        try
        {
            // Some stuff
        }
        catch (Exception e)
        {
            throw e;
        }

我知道它可以做一些事情,比如记录异常消息然后重新抛出它。我说的是一个只会重新抛出异常的捕获。我看不出这有什么意义。我有三个问题:

1)这有什么好处吗

2)这会减慢代码吗

3)如果catch块如下所示会有什么不同:

        catch (Exception)
        {
            throw;
        }
4

12 回答 12

20

这会再次引发完全相同的异常:

    catch (Exception)
    {
        throw;
    }

而这会在没有原始堆栈跟踪的情况下重新引发异常:

    catch (Exception e)
    {
        throw e;
    }

通常有一个很好的理由,throw;因为您可以在重新抛出异常之前记录异常或做其他事情。我不知道有什么好的理由,throw e;因为您将清除有价值的堆栈跟踪信息。

于 2009-07-30T15:00:12.753 回答
3

如果您在 catch 中什么都不做,则不会……但这通常用于在 catch 中执行其他操作,例如日志记录或其他类型的异常处理,然后再重新抛出它。

于 2009-07-30T15:00:02.363 回答
2

我使用这种技术,所以我可以在调试时在 throw 上放置一个断点。有时我完成后将其删除...

于 2009-07-30T15:01:13.267 回答
2

主要区别在于异常的堆栈跟踪将被更改以显示它源自第一个示例中的 try-catch 的位置。

第二个示例维护堆栈跟踪。

于 2009-07-30T15:01:19.180 回答
2

有没有优势

一般来说没有。这个模式所做的就是将堆栈跟踪重置到新的抛出点。这只会让开发人员更难追踪问题的根源

它是否会减慢代码的速度

有吗?可能。通过任何可测量的差异来减慢速度?不。

如果 catch 块如下所示,会有什么不同吗?

是的,这个捕获基本上是完全多余的。它将重新抛出异常,该异常将保持原始堆栈跟踪并且对您的应用程序没有明显影响。

于 2009-07-30T15:01:38.040 回答
1

1 - 我根本看不到任何优势。如果您不处理异常,请关闭 try/catch。这个例子的另一个问题是你没有抛出实际的异常,而是一个新的异常。

2 - 是的 - 但除非这是位于重复代码的大循环中,否则您可能不会注意到差异。

3 - 是的。在第一个示例中,您正在弄乱您的调用堆栈。此示例通过冒泡异常而不是抛出新异常来保持堆栈完整。

于 2009-07-30T15:01:25.137 回答
1

如果您真的什么都不做,那么我发现的只有一个优势:您可以throw在行上设置断点。它使它非常具体(而不是在抛出异常类型时中断)。

我只会在调试时这样做,然后将代码还原回来。

于 2009-07-30T15:01:37.447 回答
1

它通常很适合记录。此外,如果您在重新抛出时省略了参数,那么它不会改变 e 的堆栈跟踪。

有时您希望允许通过某些类型,例如这里对除 FooException 之外的所有内容进行特殊处理:

try
{
    // ...
}
catch (FooException)
{
    throw;
}
catch (Exception ex)
{
    // handle differently, like wrap with a FooException
    throw new FooException("I pitty the Foo.", ex);
}
于 2009-07-30T15:02:53.967 回答
1

我写了一个快速测试来显示差异。这是测试代码:

try
{
    var broken = int.Parse("null");
}
catch (Exception ex1)
{
    System.Diagnostics.Trace.WriteLine(ex1.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception)
    {
        throw;
    }
}
catch (Exception ex2)
{
    System.Diagnostics.Trace.WriteLine(ex2.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception ex3)
    {
        throw ex3;
    }
}
catch (Exception ex4)
{
    System.Diagnostics.Trace.WriteLine(ex4.ToString());
}

运行它,我得到以下输出:

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 18
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 33
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 49

您会注意到前两个异常的工作方式相同。所以,“扔;” 就堆栈向上移动的异常而言,不会改变任何东西。然而“抛出 ex3;” 导致报告的异常不同,从而更改异常的堆栈跟踪。

于 2009-07-30T15:08:28.730 回答
0

当然。

大多数情况下,您希望在抛出异常之前记录它,并可能从方法中记录一些变量值。

但是,仅仅抓住它并扔掉它并不能为您带来很多好处。

于 2009-07-30T15:00:21.677 回答
0

就这样,没有。但是,您可能希望这样做:

catch (Exception ex)
{
     LogException(ex);
     throw;
}

其中 LogException() 是一个自定义类,erm 记录异常或通过电子邮件发送警报或其他内容。

于 2009-07-30T15:00:50.973 回答
-1

我认为关键是要确保只抛出一种类型的异常。这是一个非常糟糕的反模式恕我直言

例如

try
{
    throw XYZ();
}
catch(Exception e)
{
    throw e;
}
于 2009-07-30T15:01:27.010 回答