当我第一次开始使用.NET编程时,我一直使用try / catches。我最近发现虽然我很少将它们用于Web应用程序。我的异常(没有双关语)是非托管代码,可能会产生内存泄漏,如com对象。他们真的需要它们还是只是把事情弄得乱七八糟?
UPDATE:假设正在使用自定义错误来处理丑陋的堆栈跟踪页面。
答案 0 :(得分:22)
我发现初级程序员使用try / catch WAY太重了。使用try / catch的决定应该归结为这些简单的规则:
你能处理错误吗? (也许这意味着要再试一次,或者使用不同的设置,返回替换值等)
你能提供更好的错误信息(更详细)吗?
您是否需要记录此特定错误? (请记住,所有错误都应该记录在最高级别 - 例如在Application_Error方法中的global.asax文件中)
您是否需要清理/处置操作中使用的资源,例如数据库连接或事务?
如果对其中任何一个回答“是”,那么请确保使用try / catch。如果您拒绝,则可以安全地允许显示错误页面并让全局错误处理程序记录它。
如果您打算记录或清理资源,但仍然允许异常通过,确保您使用throw;
而不是创建全新的例外。这样做会消除堆栈跟踪,基本上没有上下文错误。
刚从this excellent quote找到了Ayende,似乎非常好:
异常处理应该出现在 正好两个地方:
- 当出现错误时(例如,发出Web请求调用)和 有一些有意义的行为 在失败的情况下完成(例如 在经过一段时间的延迟后重试)
- 在系统边界上,在这种情况下,您需要就如何做出决定 你将把错误暴露给 外面的世界。
答案 1 :(得分:18)
以下是问题形式的答案
如果没有捕获异常,您希望如何进行错误处理?
异常(正确或错误)是.Net语言的错误机制。您根本无法编写既忽略异常又具有足够错误处理的应用程序。它根深蒂固到框架中,无法避免
答案 2 :(得分:3)
尝试捕获是编程的一个重要方面,不应该被忽略;但是,您不需要将每个语句都包含在try catch块中。通常我使用以下规则:
如果这是一个Windows应用程序,那么入口点应始终使用try catch作为捕获任何异常的最后一次尝试。在asp.net中,这是使用Application对象的OnError完成的。
如果我知道可以抛出一个特定的异常,我想处理它。例如,如果您尝试发送包含无效格式的电子邮件发送到电子邮件地址,您将收到格式异常。我可能会捕获该特定异常,并通知用户他们使用的电子邮件无效。
如果您有其他要记录的上下文信息,这对于故障排除很有用。例如,虽然我的全局asp.net错误处理程序可能会记录所有表单变量,但也许我想捕获某些对象的值。
如果你想修改应用程序的流程,例如在ASP.Net中,如果我想在我的ajax调用失败时显示错误消息,我不应该让错误气泡到我未处理的异常例程。
如果有资源需要清理,我最后使用try catch,或者尝试finally块,以确保我的资源被关闭。
答案 3 :(得分:3)
使用Finally
这样你就可以使用try-catch并仍然清理你的非托管内存。
而且,虽然确实应该避免在没有必要时尝试捕获,(例如,检查if x == null
而不是让x throw NullReferenceException
)你会发现尤其是在Web应用程序上有很多次是try-catch语句是绝对必需的,因为有时你会丢失连接,或者用户会做错事,无论你喜欢与否,都会抛出异常。
在这些情况下,您希望捕获它们,将它们捆绑在一些日志记录中,然后优雅地继续,或者释放您的资源并重新抛出。
答案 4 :(得分:2)
在正确的位置使用时,异常处理逻辑在Web域中仍然非常有用。您的后端代码可能需要连接到数据库,与其他服务进行通信,或者调用您自己的异常抛出逻辑。在任何这些情况下,您都希望捕获异常并将其传达给用户。
例如,假设您需要与已关闭的数据库进行通信。您需要将该信息发送回客户端页面,以通知用户您的网站当前已关闭或遇到问题。除非您的所有外部呼叫都返回友好状态代码(这种情况极不可能且非常繁琐),否则您将需要依赖异常。
答案 5 :(得分:0)
你应该对任何可能抛出你可以合理处理的异常的语句进行try / catch。通过合理处理,我的意思是记录,干净地关闭应用程序,发送电子邮件,尽可能修复问题,提醒用户,向异常添加信息和重新抛出等等。如果你不能做任何这些事情在一个有道理的方式,然后为什么要抓住它?话虽如此,有时候我会委托将一个异常捕获到更高级别的函数,但我很少会让异常完全没有被捕获。至少我通常可以记录错误,提醒用户并关闭应用程序。
答案 6 :(得分:0)
我想补充说,出现异常的一个关键原因是让你的应用程序能够在代码中以最合适的级别处理错误,以便用它做一些合理的事情。异常提供了一种干净的方法来将信息传递回调用堆栈以启用此功能。
决定处理各种异常的层是您的应用程序设计中的关键决策。您正在开发的应用程序类型将影响决策。
E.g。在开发Web或桌面应用程序时,仅处理非常高级别的大多数异常类型可能是完全可以接受的。当你的应用程序真的无法对错误做很多事情时,这种技术可以节省大量的代码,只需要告诉别人并记录它。
但是,在关键任务,多线程服务器应用程序中,您可能需要对异常进行细粒度控制,以便适当地处理它们并保持线程无论如何都在旋转。
答案 7 :(得分:0)
如果您愿意处理SomeException,则仅使用Catch(SomeException ex)。您不愿意处理的例外情况被视为意外情况。使用单元测试来练习代码并找到预期的异常。
以下示例是错误的,因为您没有对异常执行任何操作
try
{
// Some code that throws a exception
}
catch(Exception ex) // Only handle this type of exception in the User interface.
{
throw; // Incorrect, throwing exception for no reason
}
这样更好:
try
{
// Some code that throws a exception
}
catch(System.Data.UpdateException ex)
{
LogException(ex);
string message = DecipherException(ex);
throw new MyException(message, ex); // Incorrect
}
跟进(在用户界面中)
try
{
// Code that throws a exception
}
catch (MyException myEx)
{
// Use a nice dialog which shows the user how to fix the error
}
catch (Exception ex)
{
// Unhandled scenario - usually fatal because you didn't expect it to happen.
}