我一直听到
catch (Exception ex)
然而,不好的做法是,我经常在事件处理程序中使用它,例如,操作可能会进入网络,从而可能出现许多不同类型的故障。在这种情况下,我捕获所有异常并在消息框中向用户显示错误消息。
这被认为是不好的做法吗?除了异常之外我无能为力:我不希望它停止应用程序,用户需要知道发生了什么,而且我处于代码的顶层。我还应该做什么?
编辑:
人们说我应该查看调用堆栈并专门处理错误,因为例如StackOverflow异常无法有意义地处理。但是,暂停这个过程是最差的结果,我想不惜一切代价阻止它。如果我无法处理StackOverflow,那么就是这样 - 结果将不会比没有捕获异常更糟糕,并且在99%的情况下,就我而言,通知用户是最不好的选择。 / p>
此外,尽管我尽最大努力解决所有可能引发的异常,但在大型代码库中,我可能会错过一些。对于他们中的大多数人来说,最好的防御仍然是告知用户。
答案 0 :(得分:30)
不好的做法是
catch (Exception ex){}
和变种:
catch (Exception ex){ return false; }
等
捕获顶层的所有异常并将它们传递给用户(通过记录它们或在消息框中显示它们,具体取决于您是在编写服务器还是客户端应用程序),正确的做法。
答案 1 :(得分:18)
我发现通用捕获总是不好过分教条的论点。他们和其他一切一样,都有一席之地。
该地点不您的图书馆代码,也不是您为自定义开发的应用程序类。正如许多人所提到的,这个地方是应用程序的最高级别,如果任何异常被提出,则很可能是意外的。
这是我的一般规则(和所有规则一样,它的设计在适当的时候被破坏):
我在应用程序中使用类和自定义构建的库来进行大部分提升。这是基本的应用程序架构 - 非常基本,请注意。这些人尝试尽可能多地处理异常,如果他们真的无法继续,请将最具体的类型提供给UI。
在UI中,我倾向于始终从事件处理程序中捕获所有内容。如果有一个合理的期望捕获一个特定的异常,和我可以做些什么,然后我抓住特定的异常并优雅地处理它。但是,这必须在catch all之前,因为.NET将只使用与您的异常匹配的第一个异常处理程序。 (总是从最具体到最通用的订单!)
如果我不能对异常做任何事情而不是错误输出(例如,数据库处于脱机状态),或者异常确实是意外的,那么catch all会接受它,记录它并快速失败,在死亡之前向用户显示的一般错误消息。 (当然,有些类型的错误几乎总是会失败 - OutOfMemory,StackOverflow等等。我很幸运,没有必要处理prod级代码中的那些......到目前为止!)< / p>
抓住一切都有它的位置。那个地方不是为了隐藏异常,那个地方不是为了尝试和恢复(因为如果你不知道你抓到了什么,你怎么可能恢复),那个地方不是为了防止错误显示给用户同时允许你的应用程序继续在未知和糟糕的状态下执行。
抓住所有的位置是最后的手段,一个陷阱,以确保如果有任何东西通过你精心设计和保护良好的防御,至少它被适当记录,并可以做出干净的退出。如果你没有在较低级别设置精心设计且保护良好的防御措施,那么 是不好的做法,并且在较低级别的非常不良做法,但已完成作为最后的手段,它(在我看来)不仅可以接受,而且通常是正确的事情。
答案 2 :(得分:11)
当我看到
catch (Exception ex)
我的手开始摸索着锤子。几乎没有任何借口可以捕获基础异常。只有我想到的有效案例是:
1)第三方组件抛出异常(诅咒它的作者)
2)非常顶级的异常处理(作为最后的手段)(例如处理WinForms应用程序中的“未处理”异常)
如果您发现可能发生许多不同类型的异常的情况,则表明设计不良。
我不同意Armin Ronacher。如果引发StackOverflow异常,您会如何表现?尝试执行其他操作可能会导致更糟糕的后果。仅在您能够以有意义且安全的方式处理异常时才捕获异常。捕获System.Exception以涵盖可能异常的范围是非常错误的。即使你重新投掷它。
答案 3 :(得分:6)
在代码中的最高级别捕获异常是完全合理的。只要您不需要根据异常类型执行任何不同的逻辑,就可以捕获基类异常类型。
此外,请确保显示友好的常规错误消息,并且不显示实际的异常消息。这可能会导致安全漏洞。
答案 4 :(得分:3)
从某种意义上说,不应该在任何地方都这样做是不好的做法。
在这种情况下,我认为这是唯一合理的解决方案,因为您的例外可能是真正的任何事情。唯一可能的改进是在您捕获所有特定错误情况之前添加额外的处理程序,以便您可以对异常执行某些操作。
答案 5 :(得分:3)
是的,可以在应用程序的顶层捕获基本的Execption ,这就是你正在做的事情。
你得到的强烈反应可能是因为在任何其他级别,它几乎总是错误地捕获Base异常。特别是在一个库中,这将是非常糟糕的做法。
答案 6 :(得分:2)
如果你重新提出你无法正常处理的异常,这是完全可以的。如果你只是捕获异常,你可以隐藏你不期望的代码中的错误。如果您捕获异常以显示它们(并绕过die-and-print-traceback-to-stderr行为),这是完全可以接受的。
答案 7 :(得分:2)
我认为海报是指这样的异常处理:
try {something} catch (SqlException) {do stuff} catch (Exception) {do other stuff}
这里的想法是你想首先捕获更具体的错误(比如SqlException)并适当地处理它们,而不是总是依赖于catch-all常规异常。
传统观点认为这是进行异常处理的正确方法(并且单独的Catch(Exception ex)很糟糕)。实际上,这种方法并不总是有效,特别是当您使用其他人编写的组件和库时。
这些组件通常会根据组件在开发环境中的行为方式,在生产中抛出不同类型的异常,即使两个环境中的底层问题相同。这是ASP.NET中一个非常常见的问题,并且经常让我使用一个裸Catch(Exception ex)块,它不关心抛出什么类型的异常。
结构化异常处理在理论上是个好主意。在实践中,它仍然是您控制的代码域中的一个好主意。一旦你介绍了第三方的东西,有时候就不能很好地工作了。
答案 8 :(得分:2)
我们使用Catch ex作为Exception(VB.Net变体)相当多。我们记录它,并定期检查我们的日志。追查原因并解决。
我认为Catch ex as Exception完全可以接受一旦处理生产代码,并且您有一般方法可以优雅地处理未知异常。就个人而言,在完成模块/新功能之前,我没有把通用捕获,并对我在测试中发现的任何异常进行专门处理。这似乎是两个世界中最好的。
答案 9 :(得分:0)
没有;在这种情况下,如果您不想停止程序,那么您无法做其他任何事情,并且在顶层是正确的地方,只要您正确记录而不是将其隐藏在希望中笑容
答案 10 :(得分:0)
重要的是通过你的应用程序理解异常的路径,而不是随意抛出或捕获它们。例如,如果您捕获的异常是Out-Of-Memory会怎样?你确定在那种情况下会显示你的对话框吗?但是定义一个最后一个异常点并且说你从不希望错误传播超过那个点当然是好的。
答案 11 :(得分:0)
您应该抓住与您正在做的事情相关的例外情况。如果你看一下你调用的方法,你会看到它们抛出的异常,并且你想要更加具体。您应该有权知道您调用的方法可能引发的异常,并适当地处理它们。
而且......比尝试捕获更好,尝试捕获你需要捕获的地方。
try {
myThing.DoStuff();
}
catch (StuffGoneWrongException ex) {
//figure out what you need to do or bail
}
也许不是这么紧密,但这取决于你在做什么。请记住,这项工作不仅仅是编译它并将其放在某些桌面上,你想知道如果有什么东西会破坏什么以及如何修复它。 (在这里插入关于追踪的咆哮)
答案 12 :(得分:0)
很多时候异常被释放到免费资源,如果(重新)抛出异常并不重要。在这些情况下,您可以避免尝试捕获:
1)对于Disposable对象,您可以使用“using”关键字: 使用(SqlConnection conn = new SqlConnection(connStr)) { //码 } 一旦你超出了使用范围(通常或通过return语句或异常),就会在对象上自动调用Dispsose方法。换句话说,就像尝试/最终构建一样。
2)在asp.net中,您可以拦截Page对象的Error或UnLoad事件来释放您的资源。
我希望我帮助你!
答案 13 :(得分:0)
我正在回答“但是,暂停这个过程是最差结果......”
如果你可以通过运行不同的代码来处理异常(使用try / catch作为控制流),重试,等待和重试,使用不同但等效的技术重试(即回退方法),然后一定要这样做。
做错误消息替换和日志记录也很好,除非是伪礼貌 - 被动 - 积极的“联系你的管理员”(当你知道没有管理员,如果有管理员不能做任何事情)关于它!)但是在你这样做之后,应用程序应该结束,即与未处理的异常相同的行为。
另一方面,如果您打算通过将用户返回到可能破坏其状态的代码线程来处理异常,我会说这比结束应用程序和让出更糟糕用户重新开始。用户是否最好在开始时重新启动或更好地让用户销毁数据?
如果我在模块中遇到意外的异常,确定我可以从哪个帐户取款,我是否真的想记录并报告异常并将用户返回到取款屏幕?据我们所知,我们只是授予他从所有账户中提取资金的权利!
答案 14 :(得分:0)
这样可以捕获您可以处理的异常。但有时也会发生由于环境不稳定或用户只是正确执行该过程,应用程序会遇到意外的异常。您尚未在代码中列出或处理的内容。有没有办法从app.config文件中捕获未处理的异常并显示常见错误?
还将详细信息异常消息放入日志文件中。
答案 15 :(得分:-1)
我在异常方面做了很多工作,这是我目前正在遵循的实施结构:
我认为最近“正确”处理异常是可接受的一个例子是使用通过HTTP GET传递给页面的GUID字符串(strGuid)。我可以在调用New Guid(strGuid)之前已经实现了一个检查GUID字符串有效性的函数,但它看起来相当合理:
Dim myGuid As Guid = Nothing
Try
myGuid = New Guid(strGuid)
'Some processing here...
Catch ex As FormatException
lblError.Text = "Invalid ID"
Catch ex As Exception
Throw
Finally
If myGuid IsNot Nothing Then
myGuid = Nothing
End If
End Try