抛出和抛出新异常之间的区别()

Str*_*007 156 c#

有什么区别

try { ... }
catch{ throw } 
Run Code Online (Sandbox Code Playgroud)

try{ ... }
catch(Exception e) {throw new Exception(e.message) } 
Run Code Online (Sandbox Code Playgroud)

无论第二个显示消息?

SLa*_*aks 250

throw; 重新抛出原始异常并保留其原始堆栈跟踪.

throw ex;抛出原始异常但重置堆栈跟踪,销毁所有堆栈跟踪信息直到catch阻塞.


永远不要throw ex;


throw new Exception(ex.Message);更糟糕的是.它创建了一个全新的Exception实例,丢失了异常的原始堆栈跟踪及其类型.(例如,IOException).
此外,一些例外还包含其他信息(例如ArgumentException.ParamName).
throw new Exception(ex.Message); 也将破坏这些信息.

在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便您可以提供有关抛出异常时代码执行操作的其他信息.

为此,请定义一个继承的新类Exception,添加所有四个异常构造函数,以及可选的另外一个构造函数,该构造函数接收InnerException以及其他信息,并抛出新的异常类,作为参数传递exInnerException.通过传递原始InnerException,您可以保留所有原始异常的属性,包括堆栈跟踪.

  • "抛出新的例外(ex);更糟糕.":我不同意这一点.有时您想要更改异常的类型,然后将原始异常保持为内部异常是您可以做的最好的.虽然它应该是`抛出新的MyCustomException(myMessage,ex);`当然. (23认同)
  • 哟dawg,我们让你喜欢异常,所以我们在你的例外中放了一个例外,这样你就可以抓住了. (21认同)
  • @ 0xA3:我的意思是"ex.Message",这更糟糕. (9认同)
  • 除了实现标准构造函数之外,还应该进行自定义异常`[Serializable()]`. (6认同)
  • @SLaks:当您“抛出;”发生异常的实际行号被替换为“抛出;”的行号。您如何建议处理呢?http://stackoverflow.com/questions/2493779/wrong-line-number-on-stack-trace (2认同)
  • 跟进@DirkVollmar,如果您的代码是敏感的并且在内部消息中包含知识产权或其他敏感数据,您可能有意想要屏蔽您公开的 api 中的内部异常的所有详细信息。在这种情况下,在不提供内部异常的情况下, throw new MyCustomException(myMessage) 是有意义的。 (2认同)

Mar*_*ers 30

第一个保留原始堆栈跟踪:

try { ... }
catch
{
    // Do something.
    throw;
}
Run Code Online (Sandbox Code Playgroud)

第二个允许您更改异常的类型和/或消息和其他数据:

try { ... } catch (Exception e)
{
    throw new BarException("Something broke!");
}
Run Code Online (Sandbox Code Playgroud)

还有第三种传递内部异常的方法:

try { ... }
catch (FooException e) {
    throw new BarException("foo", e);
} 
Run Code Online (Sandbox Code Playgroud)

我建议使用:

  • 第一个如果你想在错误的情况下做一些清理而不破坏信息或添加有关错误的信息.
  • 第三个,如果你想添加有关错误的更多信息.
  • 第二个,如果你想隐藏信息(来自不受信任的用户).


Lee*_*Lee 14

这里的答案都没有显示出差异,这对于那些努力理解差异的人来说可能会有所帮助。考虑这个示例代码:

using System;
using System.Collections.Generic;

namespace ExceptionDemo
{
   class Program
   {
      static void Main(string[] args)
      {
         void fail()
         {
            (null as string).Trim();
         }

         void bareThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw;
            }
         }

         void rethrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw e;
            }
         }

         void innerThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw new Exception("outer", e);
            }
         }

         var cases = new Dictionary<string, Action>()
         {
            { "Bare Throw:", bareThrow },
            { "Rethrow", rethrow },
            { "Inner Throw", innerThrow }
         };

         foreach (var c in cases)
         {
            Console.WriteLine(c.Key);
            Console.WriteLine(new string('-', 40));
            try
            {
               c.Value();
            } catch (Exception e)
            {
               Console.WriteLine(e.ToString());
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

生成以下输出:

using System;
using System.Collections.Generic;

namespace ExceptionDemo
{
   class Program
   {
      static void Main(string[] args)
      {
         void fail()
         {
            (null as string).Trim();
         }

         void bareThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw;
            }
         }

         void rethrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw e;
            }
         }

         void innerThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw new Exception("outer", e);
            }
         }

         var cases = new Dictionary<string, Action>()
         {
            { "Bare Throw:", bareThrow },
            { "Rethrow", rethrow },
            { "Inner Throw", innerThrow }
         };

         foreach (var c in cases)
         {
            Console.WriteLine(c.Key);
            Console.WriteLine(new string('-', 40));
            try
            {
               c.Value();
            } catch (Exception e)
            {
               Console.WriteLine(e.ToString());
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

正如前面的答案中所示,裸露的抛出清楚地显示了失败的原始代码行(第 12 行)以及异常发生时调用堆栈中的其他两个活动点(第 19 行和 64 行)。

重新抛出案例的输出显示了为什么这是一个问题。当像这样重新抛出异常时,异常将不包含原始堆栈信息。请注意,仅throw e包含(第 35 行)和最外层调用堆栈点(第 64 行)。如果以这种方式抛出异常,则很难找到问题的根源fail() 方法。

最后一个案例 (innerThrow) 最为复杂,包含的信息比上述任何一个案例都多。由于我们正在实例化一个新异常,因此我们有机会添加上下文信息(此处为“外部”消息,但我们也可以添加到新异常的 .Data 字典中)并保留原始异常中的所有信息异常(包括帮助链接、数据字典等)。


Jus*_*ner 5

抛出一个新的异常会吹走当前的堆栈跟踪。

throw;将保留原始堆栈跟踪并且几乎总是更有用。该规则的例外是当您想将 Exception 包装在您自己的自定义 Exception 中时。然后你应该这样做:

catch(Exception e)
{
    throw new CustomException(customMessage, e);
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*cie 5

我没有看到有人提出的另一点:

如果您在catch {}块中什么也没做,那么try ... catch是没有意义的。我一直都这样看:

try 
{
  //Code here
}
catch
{
    throw;
}
Run Code Online (Sandbox Code Playgroud)

或更糟的是:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw ex;
}
Run Code Online (Sandbox Code Playgroud)

最糟糕的是:

try 
{
  //Code here
}
catch(Exception ex)
{
    throw new System.Exception(ex.Message);
}
Run Code Online (Sandbox Code Playgroud)

  • @ToniRossmann 在这种情况下,我会在没有捕获的情况下使用 try..finally,除非您正在做的不是 throw; (4认同)