之间有什么区别
try { ... }
catch{ throw }
和
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
无论第二个显示消息?
答案 0 :(得分:235)
throw;
重新抛出原始异常并保留其原始堆栈跟踪。
throw ex;
抛出原始异常,但重置堆栈跟踪,销毁所有堆栈跟踪信息,直到catch
阻止。
throw ex;
throw new Exception(ex.Message);
更糟糕。它创建了一个全新的Exception
实例,丢失了异常的原始堆栈跟踪及其类型。 (例如,IOException
)
此外,一些例外还包含其他信息(例如ArgumentException.ParamName
)
throw new Exception(ex.Message);
也会破坏这些信息。
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便您可以提供有关抛出异常时代码执行操作的其他信息。
为此,请定义一个继承Exception
, add all four exception constructors 的新类,以及可选的带InnerException
的其他构造函数以及其他信息并抛出新的异常类,将ex
作为InnerException
参数传递。通过传递原始InnerException
,您可以保留所有原始异常的属性,包括堆栈跟踪。
答案 1 :(得分:29)
第一个保留原始堆栈跟踪:
try { ... }
catch
{
// Do something.
throw;
}
第二个允许您更改例外的类型和/或消息和其他数据:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
还有第三种传递内部异常的方法:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
我建议使用:
答案 2 :(得分:4)
throw
重新抛出捕获的异常,保留堆栈跟踪,而throw new Exception
丢失捕获的异常的一些细节。
您通常会单独使用throw
来记录异常,而不会在那时完全处理它。
BlackWasp有一篇很好的文章标题为Throwing Exceptions in C#。
答案 3 :(得分:4)
抛出一个新的Exception会打乱当前的堆栈跟踪。
throw;
将保留原始堆栈跟踪,并且几乎总是更有用。该规则的例外是当您想要将Exception包装在您自己的自定义Exception中时。然后你应该这样做:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
答案 4 :(得分:4)
我没有看到任何人做出的另一点:
如果你在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);
}
答案 5 :(得分:3)
throw
用于重新抛出已捕获的异常。如果您想在将异常传递给调用链之前对异常执行某些操作,这将非常有用。
使用不带任何参数的throw
会保留调用堆栈以进行调试。
答案 6 :(得分:0)
如果你想要,你可以抛出一个新的异常,将原来的一个设置为内部异常。
答案 7 :(得分:0)
您的第二个示例将重置异常的堆栈跟踪。第一个最准确地保留了例外的起源。你也解开了原始类型,这是知道实际出错的关键...如果第二个是功能需要 - 例如要添加扩展信息或使用特殊类型重新换行,例如自定义'HandleableException',那么只需确保也设置了InnerException属性!
答案 8 :(得分:0)
最重要的区别是第二个表达式会删除异常类型。异常类型在捕获异常方面起着至关重要的作用:
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]
catch块将捕获异常。但是当bar()
抛出IOException
时,它将转换为普通Exception
。[1]
不会被{{1}}捕获块捕获。
答案 9 :(得分:0)
答案 10 :(得分:0)
投掷;重新抛出原始异常并保留异常类型。
抛出新的异常();重新抛出原始异常类型并重置异常堆栈跟踪
扔出去;重置异常堆栈跟踪并重置异常类型
答案 11 :(得分:-1)
这里没有答案显示出差异,这可能有助于努力了解差异的人们。考虑以下示例代码:
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字典中),并将所有信息保留在原始信息中异常(包括帮助链接,数据字典等)。