抛出异常是否具有不仅仅是构造异常的副作用
本文关键字:异常 副作用 不仅仅是 是否 抛出异常 | 更新日期: 2023-09-27 17:56:22
我脑子里有抛出异常有副作用(比如收集堆栈信息),但我意识到它可能不会。以下两个版本的GetException
之间有区别吗?
public Exception GetException() {
try {
throw new Exception("Bummer");
}
catch (Exception e) {
return e;
}
}
public Exception GetException() {
return new Exception("Bummer");
}
引发异常时,堆栈跟踪将"插入"到异常中(这是您可以通过 StackTrace
属性获取的内容)。所以是的,抛出异常对象有一个副作用。
重新抛出异常的问题(即使
throw;
是堆栈跟踪被破坏(甚至覆盖,如果您使用 throw ex;
))
请注意,throw;
比 throw ex;
更好,因为第一个只会破坏一点行号,而后者将完全重置堆栈跟踪。
有些人不信任...查看 https://dotnetfiddle.net/RXicN9 并检查行号。他们是不同的。
一个更完整的示例,显示只有具有两个try... catch...
的方法的行号被篡改: https://dotnetfiddle.net/jJyYWB
有关说明,请参阅通过重新抛出的错误堆栈跟踪。请注意,这是一种特殊情况,仅当在同一方法中引发两次异常时才会发生。
是的,两者是不同的。throw
将修改 Exception
对象中的堆栈跟踪信息 - 因此您的第二个示例仍将生成异常,但没有堆栈跟踪信息。
Exception
派生类是与其他类一样的类 - 所有的"魔术"都发生在throw
关键字上。
这也是为什么通过执行throw ex;
来重新抛出异常是一个坏主意的原因 - 您要么想使用throw;
(尽管以Xanatos指出的相同方法小心重新抛出的问题),要么想要包装内部异常(即。 throw new MyException(ex)
)。在这两种情况下,仍然有一些小的更改可能会使调试复杂化,但如果你做好了充分的准备,它会有很大帮助。
这种行为实际上非常有用。首先,这意味着您可以使用帮助程序方法来构造要引发的异常(这在 .NET 代码本身中随处可见)。第二,它允许运行时实际抛出StackOverflowException
和OutOfMemoryException
等异常 - 两者都在应用程序启动时创建其实例,当问题发生时,它们只会抛出 - 当然,new
会失败。