之间有什么区别
try { ... }
catch{ throw }
和
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
不管第二个显示一条消息?
之间有什么区别
try { ... }
catch{ throw }
和
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
不管第二个显示一条消息?
Answers:
throw;
重新抛出原始异常并保留其原始堆栈跟踪。
throw ex;
引发原始异常,但会重置堆栈跟踪,破坏所有堆栈跟踪信息,直到您的catch
块为止。
throw ex;
throw new Exception(ex.Message);
更糟的是 它创建一个全新的Exception
实例,丢失该异常的原始堆栈跟踪及其类型。(例如IOException
)。
此外,某些例外情况还包含其他信息(例如ArgumentException.ParamName
)。
throw new Exception(ex.Message);
也会破坏这些信息。
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便可以提供有关引发异常时代码在做什么的其他信息。
为此,请定义一个继承的新类Exception
,添加所有四个异常构造函数,还可以选择一个InnerException
同时包含和其他信息的附加构造函数,然后将新的异常类作为参数传递ex
给您InnerException
。通过传递original InnerException
,可以保留所有原始异常的属性,包括堆栈跟踪。
throw new MyCustomException(myMessage, ex);
。
ex.Message
,这是雪上加霜。
[Serializable()]
。
第一个保留原始的堆栈跟踪:
try { ... }
catch
{
// Do something.
throw;
}
第二个允许您更改异常和/或消息及其他数据的类型:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
还有第三种方法可以传递内部异常:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
我建议使用:
我没有看到有人提出的另一点:
如果您在catch {}块中没有执行任何操作,那么try ... 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);
}
throw
重新引发捕获的异常,保留堆栈跟踪,而throw new Exception
丢失捕获的异常的某些详细信息。
通常throw
,您通常会单独使用它来记录异常,而此时并没有完全处理它。
BlackWasp有一篇很好的文章,标题为《C#中的Throwing Exceptions》。
抛出新的Exception会破坏当前的堆栈跟踪。
throw;
将保留原始堆栈跟踪,并且几乎总是更有用。该规则的例外是您希望将Exception包装在您自己的自定义Exception中。然后,您应该执行以下操作:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
您的第二个示例将重置异常的堆栈跟踪。第一个最准确地保留了异常的起源。另外,您已经解开了原始类型,这对于了解实际出了问题是很关键的...如果第二个功能是必需的-例如,要添加扩展信息或使用特殊类型(例如自定义“ HandleableException”)重新包装,则只需确保也设置了InnerException属性!
最重要的区别是第二个表达式删除了异常类型。异常类型在捕获异常中起着至关重要的作用:
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]
catch块捕获。
throw或throw ex,这两者都用于抛出或重新抛出异常,当您只是简单地记录错误信息而又不想将任何信息发送回给调用者时,您只需在catch和离开中记录错误。但是,如果您想将有关异常的一些有意义的信息发送给使用throw或throw ex的调用方。现在throw和throw ex之间的区别是throw保留了堆栈跟踪和其他信息,但是throw ex创建了新的异常对象,因此原始的堆栈跟踪丢失了。因此,何时应该使用throw and throw e,在某些情况下,您可能想重新抛出异常,例如重置调用堆栈信息。例如,如果该方法在库中,并且您想从调用代码中隐藏该库的详细信息,您不一定希望调用堆栈在库中包含有关私有方法的信息。在这种情况下,您可以在库的公共方法中捕获异常,然后重新抛出它们,以便调用堆栈从这些公共方法开始。
这里没有任何答案能显示出差异,这可能对努力了解差异的人们有所帮助。考虑以下示例代码:
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字典中),并将所有信息保留在原始信息中异常(包括帮助链接,数据字典等)。