两者有什么区别
try { ... }
catch{ throw }
and
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
不管第二个显示的是一条消息。
两者有什么区别
try { ... }
catch{ throw }
and
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
不管第二个显示的是一条消息。
当前回答
扔;重新抛出原始异常并保留其原始堆栈跟踪。
把交货;抛出原始异常,但重置堆栈跟踪,在catch块之前销毁所有堆栈跟踪信息。
永远不要写throw ex;
抛出新的异常(ex.Message);更糟糕。它创建了一个全新的Exception实例,丢失了异常的原始堆栈跟踪及其类型。(例如,IOException)。 此外,一些异常包含额外的信息(例如,ArgumentException.ParamName)。 抛出新的异常(ex.Message);也会毁掉这些信息。
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便您可以提供有关抛出异常时代码正在做什么的附加信息。
为此,定义一个继承Exception的新类,添加所有四个异常构造函数,并可选地添加一个额外的构造函数,该构造函数接受一个InnerException以及其他信息,并抛出您的新异常类,将ex作为InnerException参数传递。通过传递原始的InnerException,可以保留所有原始异常的属性,包括堆栈跟踪。
其他回答
还有一点我没看到有人说:
如果你没有在catch{}块中做任何事情,尝试一下…捕捉是没有意义的。我经常看到这样的情况:
try
{
//Code here
}
catch
{
throw;
}
或者更糟:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
坏的:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
最重要的区别是第二个表达式删除了异常的类型。异常类型在捕获异常方面起着至关重要的作用:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
如果foo()抛出IOException,[1]捕获块将捕获异常。但是当bar()抛出IOException时,它将被转换为普通异常,并且不会被[1]捕获块捕获。
扔;重新抛出原始异常并保留其原始堆栈跟踪。
把交货;抛出原始异常,但重置堆栈跟踪,在catch块之前销毁所有堆栈跟踪信息。
永远不要写throw ex;
抛出新的异常(ex.Message);更糟糕。它创建了一个全新的Exception实例,丢失了异常的原始堆栈跟踪及其类型。(例如,IOException)。 此外,一些异常包含额外的信息(例如,ArgumentException.ParamName)。 抛出新的异常(ex.Message);也会毁掉这些信息。
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便您可以提供有关抛出异常时代码正在做什么的附加信息。
为此,定义一个继承Exception的新类,添加所有四个异常构造函数,并可选地添加一个额外的构造函数,该构造函数接受一个InnerException以及其他信息,并抛出您的新异常类,将ex作为InnerException参数传递。通过传递原始的InnerException,可以保留所有原始异常的属性,包括堆栈跟踪。
throw重新抛出捕获的异常,保留堆栈跟踪,而throw new exception丢失捕获的异常的一些细节。
通常使用throw本身来记录异常,而不完全处理它。
BlackWasp有一篇很好的文章,标题是c#中抛出异常。
这里的答案都没有显示出差异,这可能有助于那些努力理解差异的人。考虑下面的示例代码:
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());
}
}
}
}
}
生成如下输出:
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
正如前面的回答中所指出的,裸抛出清楚地显示了失败的原始代码行(第12行)以及异常发生时调用堆栈中活动的另外两个点(第19行和第64行)。
重新抛出案例的输出显示了为什么这是一个问题。当像这样重新抛出异常时,异常将不包括原始堆栈信息。注意,只包括throw e(第35行)和最外层的调用堆栈点(第64行)。如果以这种方式抛出异常,则很难将fail()方法作为问题的根源。
最后一种情况(innerThrow)是最详细的,包含的信息比上面任何一种都要多。因为我们正在实例化一个新的异常,所以我们有机会添加上下文信息(这里是“外部”消息,但我们也可以在新异常上添加到. data字典中),以及保留原始异常中的所有信息(包括帮助链接、数据字典等)。