【问题标题】:In .NET, is there any advantage to a try/catch where the catch just rethrows [duplicate]在.NET中,try / catch是否有任何优势,其中catch只是重新抛出[重复]
【发布时间】:2009-07-30 14:58:20
【问题描述】:

可能重复:
Why catch and rethrow Exception in C#?

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

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

我了解可以执行诸如记录异常消息然后重新抛出它之类的操作。我说的是一个只会重新抛出异常的捕获。我看不出这有什么意义。我有三个问题:

1) 这样做有什么好处

2) 这是否会减慢代码速度

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

        catch (Exception)
        {
            throw;
        }

【问题讨论】:

标签: c# .net try-catch


【解决方案1】:

这会重新抛出 exact 相同的异常:

    catch (Exception)
    {
        throw;
    }

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

    catch (Exception e)
    {
        throw e;
    }

throw; 通常有充分的理由,因为您可以在重新抛出异常之前记录异常或执行其他操作。我不知道throw e; 有什么好的理由,因为你会清除有价值的堆栈跟踪信息。

【讨论】:

  • 后者几乎不应该被使用,尽管有人可能会争辩说前者也不应该在你提供的化身中使用(至少不添加某种形式的日志记录)。
  • @Andrew,据我了解,变量 e 是指向堆上同一个异常对象的指针......你是说在堆上创建了一个新的异常对象吗?或者只是创建了一个新的 ref 变量“e”?如果是前者,你有这个花絮的参考吗?
  • @Charles - 很高兴指出 - 我一直认为这是一个新异常,但一些调查帮助我了解到这两种情况实际上是完全相同的异常实例。
  • @Andrew,那我很好奇,(我会对此做更多的研究),为什么第一个语法包含堆栈跟踪但第二个语法丢失它?
  • 就我个人而言,我很喜欢这种内部异常。使用您自己的消息引发新的异常,但附加最初导致错误的异常。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 为什么不直接使用堆栈跟踪来确定生成 throw 的代码行?
    • 这个技巧不是要知道异常在哪里被抛出(你可以为此打开 CLR 异常调试)——当你有一个断点时,你有 QuickWatch,这通常足以解决原因的例外。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      有没有优势

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

      它是否会减慢代码速度

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

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

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

      【讨论】:

      • +1 表示最后一条语句!
      【解决方案6】:

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

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

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

      【讨论】:

        【解决方案7】:

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

        我只会在调试时这样做,然后恢复代码。

        【讨论】:

          【解决方案8】:

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

          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;”导致报告的异常不同,从而更改异常的堆栈跟踪。

          【讨论】:

            【解决方案9】:

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

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

            try
            {
                // ...
            }
            catch (FooException)
            {
                throw;
            }
            catch (Exception ex)
            {
                // handle differently, like wrap with a FooException
                throw new FooException("I pitty the Foo.", ex);
            }
            

            【讨论】:

              【解决方案10】:

              当然。

              您通常希望在抛出异常之前记录它,并可能从方法中记录一些变量值。

              不过,仅仅抓住它并扔掉它并没有给你带来很多好处。

              【讨论】:

                【解决方案11】:

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

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

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

                【讨论】:

                  【解决方案12】:

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

                  例如

                  try
                  {
                      throw XYZ();
                  }
                  catch(Exception e)
                  {
                      throw e;
                  }
                  

                  【讨论】:

                  • 不会捕获任何类型的异常并重新抛出它吗?
                  • 这就是为什么该声明没有任何意义。
                  • 它将捕获任何类型的异常并将其作为“异常”类型的异常重新抛出,从而删除类型信息。我想。
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-10-03
                  • 1970-01-01
                  • 2021-08-27
                  • 2017-04-11
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多