异常构造函数类
本文关键字:构造函数 异常 | 更新日期: 2023-09-27 18:36:27
当我使用它时,它是一样的吗:
catch(Exception e)
{
throw new Exception("some Exception", e);
}
而这个:
catch(Exception e)
{
throw new Exception("some Exception", e.InnerException);
}
还是我错过了什么?
在第二个示例中,您将丢弃捕获的异常,而是使用其内部异常。您通常会像第一个示例中一样编写代码。
在第一种情况下,捕获的异常 ( e
) 成为您抛出的新异常的InnerException
:
catch(Exception e)
{
throw new Exception("some Exception", e);
}
在第二种情况下,您使用的是 e
的InnerException
,并且来自e
的数据将丢失:
catch(Exception e)
{
throw new Exception("some Exception", e.InnerException);
}
第一个例子一般来说更正确。 当您抛出一个新异常作为另一个异常的结果时,您应该将原始异常作为新异常的内部异常包含在内。
不过,这并非普遍正确。 在某些非常特殊的情况下,它很有用,因为您希望撤消另一个代码对真正错误的包装。
try {
// some reflection call
} catch (TargetInvocationException e) {
// Reduce the layers of data a developer has to dig through by using the real
// exception when I re-wrap
throw new MyException("some message", e.InnerException);
}
三种方法可以重新引发异常:
catch (Exception ex)
{
throw;
}
引发原始异常,并保留原始堆栈跟踪。
catch (Exception ex)
{
throw ex;
}
引发原始异常,但原始堆栈跟踪丢失。堆栈跟踪现在将此行显示为异常的发起方。
catch (Exception ex)
{
throw new Exception("...", ex);
}
引发新异常,但保留原始异常及其堆栈跟踪作为新异常的InnerException
。
第一种情况很有用,您需要清理失败而不是成功。如果你需要在这两种情况下进行清理,你将使用 finally 子句,而不是 catch 子句。或者,您只想记录此处发生的异常,并让调用方处理它。
第二种情况根本没有用处。为什么要隐藏堆栈跟踪?在极少数情况下,这可能是有用的,但我知道没有。
当您想要返回单一类型的异常(或类型系列)时,最常使用第三种情况。例如,您是一个文本解析方法,您希望将所有(非致命)异常转换为 ParseException(或其他任何异常),从而提供其他详细信息,例如发生异常的文本中的行号。
在您提供的第二个示例中,捕获的异常将被完全丢弃。将生成一个新的异常,并且原始异常的 InnerException 将成为此新异常的 InnerException。我无法想象剥离中间异常的任何情况都是有用的。