我发现了一个例外!怎么办?


69

我已经开始使用try-catch块(有点晚了,我知道!),但是现在我不知道一旦捕获到异常,该如何处理。我该怎么办?

Try
    connection.Open()
    Dim sqlCmd As New SqlCommand("do some SQL", connection)
    Dim sqlDa As New SqlDataAdapter(sqlCmd)
    sqlDa.Fill(dt)
Catch ex As SQLException
    ' Ahhhh, what to do now!!!?
Finally
    connection.Close()
End Try

72
拿一个玻璃罐,在盖子上戳一些孔;-)
KM。

28
例外:必须抓住一切!
CiscoIPPhone

14
令人敬畏的标题:)
艾哈迈德·玛吉德

5
-幸运,它没有抓住!:))
mlvljr

10
在苏联,俄罗斯这样做。
Ty W

Answers:


64

异常处理的经验法则-如果您不知道如何处理它,请不要抓住它。

处理异常的经验法则的推论-在最后一个负责的时刻处理异常。如果您不知道这是否是最后一个负责任的时刻,那不是。


2
我不同意这一点,并修改了答案以反映原因。
NibblyPig 2010年

2
@SLC-将和我已经解释了确切的原因。如果您无法做一些有用的事情,并且产生了异常,那么就没有理由在那儿捕获它。这是一个设计问题。图书馆就是一个很好的例子。当然,如果您没有AppDomain.UnhandledException处理程序而一直冒泡到顶部,则完全是另一个问题。关于这一点,SLC要明确一点,我不建议忽略异常。
Sky Sanders

4
然后,我认为我们都对彼此在说什么感到困惑。再次阅读答案。如果您不知道如何处理异常,请不要捕获它。因此,由于一百万个原因之一,您的数据库可能会引发更新异常-您是说,如果您不知道如何处理该异常,则不应捕获该异常。没有什么比这更错了。想象一下,如果它由于您的防病毒软件阻止了它而引发了SQL异常,这是您从未预料到的。您应该捕获并显示异常,让它们继续运行,而不是忽略它并让程序崩溃并刻录。
NibblyPig 2010年

2
硬盘或网络延迟,无论是否正在捕获异常,无论如何都为时已晚。让该死的事情在调用堆栈中冒泡,并在应用程序的顶层处理奇怪的系统故障。
詹姆斯·韦斯特盖特

4
您好reddit。感谢所有代表提供的如此出色的答案。今天,我的回答会有所不同。我还要提出一个推论:在最后一个负责的时刻处理异常。如果您不知道这是否是最后一个负责任的时刻,那不是。

23

你想让我做什么?这完全取决于您的应用程序。

您可以重试它,可以在屏幕上显示消息框,写日志,可能性无穷无尽。

作为开发人员,您无法预测所有可能的错误。即使您不知道如何解决错误,也最好有一个通用的捕获代码。您可能正在保存到数据库,并且可能会发生50个数据库错误之一,并且您将无法编写处理每个错误的代码。

您应该加入一个通用的陷阱,以确保您的程序不会简单地崩溃,并且在某些情况下,仅显示错误并让它们再执行一次就足够了。想象一下原因是否为“磁盘已满”。您只可以打印出异常,然后让用户重试-他们会知道该怎么办,自己解决问题。

这就是为什么我不同意关于如果您不知道该怎么办不进行处理的评论的原因。即使它只是显示一个显示“错误”的消息框,也应始终进行处理,因为它比“该程序执行了非法操作并将被关闭”绝对好。


1
@Victor Hurdugaci认为异常不会致命,除非程序要求该数据正在运行。我总是尝试不结束程序,因为通常您可以让用户再试一次,再试一次,让他们知道出了点问题,让用户知道该怎么做。我不喜欢我一直用来关闭程序的程序。
msarchet 2010年

13
“您应该始终处理[例外]”。我不能再与你不同意。许多语言为无法处理的异常提供了最后机会。在最后一步,让您处理无法处理的异常或不知道如何处理的异常,并向用户显示一个漂亮的“ You're F-ed”对话框。

3
@SLC Will意味着您可以通过添加一个通用的异常处理程序来防止程序崩溃:您无需在每个例程都添加异常处理。退房的文件msdn.microsoft.com/en-us/library/...
MarkJ

1
@Baron您几乎可以看出,将文本放入文本框的某些代码不会中断,但是连接到数据库并更新记录或写入日志文件的代码很可能会中断。您可能有全局错误捕获代码,但我看不到这是件好事,尤其是如果仅通过警告对话框可以忽略某些错误(“未写入日志:磁盘已满”)时,尤其如此。没有针对每个错误的全局解决方案,因此依靠全局捕获异常不是一个好的解决方案,而是更多的故障保护方法。在涉及到这一点之前,您应该先做好准备
NibblyPig 2010年

1
我不同意,不良的异常处理比没有异常处理更糟糕。快速失败的原理如何?我了解在UI或框架代码中(例如在线程池中)进行通用的异常处理,但是您必须非常小心,不要捕捉太多。没有什么比像API的代码捕获异常,记录日志(打印它,以其他方式)并在没有给调用者一个处理它的机会的情况下快乐地运行更糟糕的了。如果有人不知道该怎么办,我建议他们不要处理它,我会感到很舒服。
juancn 2011年

20

这取决于您的业务逻辑,但是您可能需要执行以下一项或多项操作。

  • 回滚您的交易
  • 记录错误
  • 提醒任何用户该应用程序
  • 重试该操作
  • 抛出异常

您可能还希望检查异常是否属于您可以在上述条件之一之前处理的类型。

关于VB.NET异常处理的好文章是Rajesh VS的VB.NET中异常处理


14

如果您不知道如何处理它,我看到很多建议不要抓住它。那只是一种权利。您应该捕获异常,但可能不在此级别。以您的代码为例,我会这样写:

Using connection As New SqlConnection("connection string here"), _
      sqlCmd As New SqlCommand("do some SQL", connection), _
      sqlDa As New SqlDataAdapter(sqlCmd)

    sqlDa.Fill(dt)
End Using

不仅没有尝试/捕获/最后,也没有打开或关闭。.Fill()函数被记录为在需要时打开连接,并且using块将绝对确定它已正确关闭,即使抛出异常也是如此

这使您可以自由地在更高级别上捕获异常-在UI或业务代码中,然后在查询运行的地方调用该函数,而不是直接在查询本身处。此更高级别的代码可以更好地决定如何进行操作,需要进行哪些日志记录或向用户显示更好的错误消息。

实际上,正是这种使异常在代码中“冒泡”的能力使它们变得如此有价值。如果您总是在抛出异常的地方捕捉到异常,那么除了vb的旧“ On Error Goto X”语法外,异常不会带来太多价值。


9

这取决于SQL实际情况。是吗:

  • 用户做到了吗?也许创建一个帐户或一条消息-然后您需要通知用户出事了
  • 该应用程序自然可以做到吗?喜欢清理日志或类似的东西吗?致命吗?申请可以继续吗?这是可以忽略的东西-也许重试了吗?是否应该宣布管理员?

从这些问题开始,它们通常会导致有关如何处理异常的答案


5

除非您期望错误(API指出它可能发生)并且可以处理它(如果发生异常,显然要采取一个步骤),否则您可能希望崩溃并产生很多噪音。这应该在测试/调试期间发生,以便可以在用户看到错误之前对其进行修复!

当然,正如评论员指出的那样,用户永远都不应真正看到所有这些噪音。可以使用高级try/catch方法或其他方法(EMLAH,我听说过.net Web项目)向用户显示一条不错的错误消息(“糟糕!出了点问题!您到底想做什么?”)提交按钮...

所以基本上,我的意思是:不要捕获您不知道如何处理的错误!(高级处理程序除外)。尽早崩溃,并提供尽可能多的信息。这意味着您应尽可能记录调用堆栈和其他重要信息以进行调试。


3
另一方面,永远不要在用户眼前“因大量噪音而崩溃”。这样说:“糟糕,出现了问题,我们正在努力。” 没有公开的细节。

4
最好在自定义页面上显示“请告诉我们您在做什么”文本框并提交按钮,以便他们发泄。当然,不要将其连接到任何东西。
NibblyPig 2010年

2

如果不知道如何应对,请不要捕获异常。

而是在有可能处理它并且知道如何继续执行的地方捕获它。


2

要记住的一件事是,在您确实希望使用try / catch的部分中,应将Dim语句移出try块。您可以在块内分配它们的值,但是如果在try块内定义它们的值,则将无法访问catch部分内的那些变量,因为此时它们将超出范围。

我在catch块中的标准做法(包括尝试尽可能地纠正错误)是使用导致错误的部分中涉及的关键变量的信息,写出我正在使用的任何记录机制。这不是必需的,但我发现它通常有助于调试问题。


2

我想向您建议,如果您不知道如何处理异常,请不要捕获它。编码人员常常会捕获异常,然后将其全部吞下。

catch (Exception ex)
{
  /* I don't know what to do.. *gulp!* */
}

显然这不好,因为坏事正在发生,并且没有采取任何措施。仅捕获可操作的异常!

就是说,优雅的错误处理很重要。不想让您的应用程序崩溃,对吗?您可能会发现ELMAH对于Web应用程序很有用,并且为WinForms或XAML桌面应用程序设置全局异常处理程序非常容易。

综上所述,您可能会发现此策略很有用:1.捕获已知可能发生的特定异常(DivideByZeroException,SQLException等),并避开通用的“万能捕获”异常;2.处理异常后,重新引发它。例如

catch (SQLException ex)
{
  /* TODO: Log the error somewhere other than the database... */
  throw; // Rethrow while preserving the stack trace.
}

您实际上可以使用SQLException做什么?数据库连接是否消失了?查询不好吗?您可能不想为此添加所有处理逻辑,此外,如果您没有想到该怎么办?因此,请尽可能处理异常,重新引发它,除非您确定它已解决,然后在全局范围内优雅地处理它。(例如,显示类似“消息出了错,但您仍可以继续工作。信息:“ [ex.Message]”。中止还是重试?”)

HTH!

约翰·桑德斯(John Saunders),感谢您的纠正。


2
仔细记录并重新抛出。如果您在每个级别进行日志记录,最终可能会在错误日志中出现许多相同异常的条目。Google“重新记录日志”,以获取正确方法的一些提示。
WCWedin

@JohnSaunders既然答案已经确定,您应该考虑删除您的评论。
马克·赫德

@Mark:谢谢。我不知道有什么变化。Downvote已删除。
约翰·桑德斯


1

仅供参考,您不必使用catch即可发出finally语句。

有时,人们会抛出一个新的异常,该异常更令人讨厌,并将原始异常添加为内部异常。

通常,这用于将错误记录到文件或向操作员发送电子邮件。

有时,尤其是在SQL中,它可能仅表示重复的键,例如,请选择另一个已经使用的用户名-这完全取决于您的应用程序。


0

我会考虑记录发生了异常,并通知用户您无法完成他们的请求。假定此SQL请求对于完成用户尝试执行的操作是必需的。


0

这完全取决于上下文。可能的选项包括“使用默认数据而不是数据库中的数据”和“向用户显示错误消息”。


0

如果您不想对其进行任何操作,则总是可以尝试/最终尝试,而不是try / catch / finally


0

根据应用程序的类型,考虑使用全局日志记录处理程序(即ASP.NET应用程序的“ Application_Error”)或使用预先构建的开源或MSFT提供的异常处理框架。

异常处理应用程序块建议使用作为企业库5.0一部分。

除了日志记录之外,我同意不需要明确地捕获异常,除非您需要对它们进行有意义的操作。最糟糕的错误就是先“捕获”然后再次“抛出”,因为这会使StackTrace混乱。


0

好吧,这主要取决于您是否从应用程序中赚钱。根据我的经验,没有人(为应用程序付费)喜欢看到它崩溃和关闭,相反,他们更喜欢有关该错误的简短说明性消息,以及第二次继续执行所做的操作的机会,以及保存/导出已修改内容的机会。数据。IMO的最佳做法是捕获可能导致无法控制的错误的所有内容,例如I / O操作,与网络相关的任务等,并向用户显示相关的消息。如果由于与逻辑相关的错误而引发异常,则最好不要捕获该异常,因为这将帮助您查找和更正实际错误。

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.