在当前项目的各个代码部分中,经常使用
try
{
//code
}
catch(Exception e)
{
//display nicely formatted error message
}
我的问题是,假设代码处理所有已知/假定的错误(例如检查对象是否为空等),是否应该在以应用程序全局格式显示错误的代码周围放置一个 try-catch?
还是让错误引发异常并让应用程序自然崩溃是更好的做法?
谢谢
在当前项目的各个代码部分中,经常使用
try
{
//code
}
catch(Exception e)
{
//display nicely formatted error message
}
我的问题是,假设代码处理所有已知/假定的错误(例如检查对象是否为空等),是否应该在以应用程序全局格式显示错误的代码周围放置一个 try-catch?
还是让错误引发异常并让应用程序自然崩溃是更好的做法?
谢谢
像这样捕获所有异常不是一个好习惯,除非在应用程序的顶层,您会在其中显示一个很好的错误消息。做得对,它可以保持最终用户对您的程序的看法,即稍微有问题,但总体上是合理的。相比之下,让您的应用程序崩溃是让您的最终用户相信您的应用程序已经无法修复的最简单方法。
就异常预防而言,主要有两种异常——编程错误(空指针、类转换、超出范围等)和环境错误(找不到文件、网络路径不可用、用户输入错误等)。 ) 你可以而且应该避免第一种,并准备好处理第二种。
class PerformTask
{
public void ConnectToDB(requiredParams)
{
}
}
class PerformTaskConsumer
{
public void SomeMethod()
{
try
{
PerformTask obj = new PerformTask();
}
catch(RelaventExceptions)
{
}
}
}
如果可以,请避免异常。如果发生异常,将它留给调用者他想对异常做什么。调用者可能决定显示有关异常的格式正确的消息,或者决定崩溃或其他任何情况。
Eric Lippert 有一篇关于异常的好文章。这里
这里有两种截然不同的思想流派,两者的支持者常常对任何人都可能相信另一种方式感到震惊和惊讶。最后,这是一个偏好问题,以及您的目标用户群期望和/或愿意接受什么,更重要的是,您对应用程序功能的了解程度如何。(您的问题意味着您没有编写所有涉及的代码,因此最后一点可能比您想象的要棘手。)
首先,我假设您在这里谈论的是最终用户应用程序,而不是类库。几乎没有充分的理由在您没有明确处理的类库中捕获异常。你总是把决定权留给来电者。
但是,在最终用户应用程序中,最终决定权在您手中,因为调用链上没有任何人。在这种情况下,您有两个广泛的选择:
有些人认为,当遇到错误时,最好让应用程序在物理上尽快崩溃。虽然这似乎有点适得其反,但请记住遇到未处理的异常意味着什么:您实际上不知道出了什么问题;甚至像您的错误记录代码这样简单的事情也可能以您不期望的方式运行。
如果您在调用站点正确处理异常,则只有在发生非常非常糟糕的事情时才会收到这种“意外”错误:内存不足、堆栈损坏等。那种你无法真正恢复的事情,无论如何,所以尝试没有意义。
其他人认为您应该尽可能地隔离错误,以防止您的用户丢失信息。如果您的应用程序足够模块化,那么一个区域的完全故障可能对另一个区域的数据完全没有影响。
这是一个风险更大的提议:您必须非常小心,不要让自己处于不一致的状态。它要求您确定地知道,失败代码中的任何内容都不会从代码的其他部分改变状态。
像往常一样,“正确”的答案可能在中间的某个地方。一般来说,在不一致的状态下运行的风险几乎总是让应用程序死掉的好理由。当然,您可能仍希望在此处进行某种程度的日志记录,您可以通过多种方式完成。我的偏好不是为此使用异常,而是挂钩到顶层的各种“未处理异常”事件,例如this、this或this。在这些事件处理程序中记录您的异常,可能会显示一个“更友好”的错误对话框,然后让您的应用程序关闭。例如,我们在我们生成的 WPF 应用程序中放置了类似的内容:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DispatcherUnhandledException="UnhandledException">
private void UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
logger.FatalException("OH NOES! Bad stuff happened, bailing out.", e.Exception);
MessageBox.Show("holy cow something bad happened:\r\n" + e.Exception.Message);
}
但是,有些地方捕获所有异常可能是安全的;这主要限于无论如何都会丢弃所有数据的地方。例如,打印或导出已完成操作的结果可能会“安全地”失败,而不会对应用程序的其余部分产生不良影响。您可能不希望您的应用程序因为用户没有打印机而崩溃。(我什至遇到过一个第三方打印库明确抛出System.Exception
错误的案例......)但是您必须非常小心,您知道自己在做什么,并且您的数据真正与其他数据隔离系统的。
提示您知道在哪里放置 try ... catch 块。
放置一个全局异常处理程序,以捕获所有未处理的异常。记录堆栈跟踪和异常,向最终用户道歉并关闭程序(永远不要尝试在此处继续)。
让应用程序运行,当它崩溃时,检查原因并使用最具体的异常正确处理异常。
请记住: 异常是针对异常,而不是针对正常的程序行为。