繁体   English   中英

捕获.NET中的异常类

[英]Catching base Exception class in .NET

我一直听到这个

catch (Exception ex)

然而,不好的做法是,我经常在事件处理程序中使用它,例如,操作可能会进入网络,从而可能出现许多不同类型的故障。 在这种情况下,我捕获所有异常并在消息框中向用户显示错误消息。

这被认为是不好的做法吗? 除了异常之外我无能为力:我不希望它停止应用程序,用户需要知道发生了什么,而且我处于代码的顶层。 我还应该做什么?

编辑:

人们说我应该查看调用堆栈并专门处理错误,因为例如StackOverflow异常无法有意义地处理。 然而,停止这个过程是最糟糕的结果,我想不惜一切代价阻止这一过程。 如果我无法处理StackOverflow,那么就是这样 - 结果将不会比没有捕获异常更糟糕,并且在99%的情况下,就我而言,通知用户是最不好的选择。

此外,尽管我尽最大努力解决可能引发的所有可能异常,但在大型代码库中,我可能会错过一些。 对于他们中的大多数人来说,最好的防御仍然是告知用户。

不好的做法是

catch (Exception ex){}

和变种:

catch (Exception ex){ return false; }

等等

捕获顶层的所有异常并将它们传递给用户(通过记录它们或在消息框中显示它们,具体取决于您是在编写服务器还是客户端应用程序),这是正确的做法去做。

我发现泛型捕获总是不好过分教条的论点。 他们和其他一切一样,都有一席之地。

那个地方不是您的图书馆代码,也不是您为自己的应用程序定制开发的课程。 正如许多人所提到的,这个地方是应用程序的最高级别,如果引发任何异常,则很可能是意外的。

这是我的一般规则(和所有规则一样,它的设计在适当的时候被破坏):

我在应用程序中使用类和自定义构建的库来完成大部分工作。 这是基本的应用程序架构 - 非常基本,请注意。 这些人尝试尽可能多地处理异常,如果他们真的无法继续,请将最具体的类型提供给UI。

在UI中,我倾向于始终从事件处理程序中捕获所有内容。 如果有合理的期望捕获特定的异常, 并且我可以对它做些什么,那么我会捕获特定的异常并优雅地处理它。 但是,这必须在catch all之前,因为.NET将只使用与您的异常匹配的第一个异常处理程序。 (总是从最具体到最通用的订购!)

如果我不能对异常做任何事情而不是错误输出(例如,数据库处于脱机状态),或者异常确实是意外的,那么catch all将接受它,记录它并快速失败,并带有一般错误消息在临终前显示给用户。 (当然,某些类型的错误几乎总是会失败 - OutOfMemory,StackOverflow等等。我很幸运,没有必要处理prod级代码中的那些......到目前为止!)

抓住一切都有它的位置。 那个地方不是为了隐藏异常,那个地方不是为了尝试和恢复(因为如果你不知道你抓到了什么,你怎么可能恢复),那个地方不是为了防止错误显示给用户同时允许你的应用程序继续在未知和糟糕的状态下执行。

抓住所有的地方是最后的手段,一个陷阱,以确保如果有任何东西通过你精心设计和保护良好的防御,至少它被适当记录,并可以做出干净的退出。 坏的做法,如果你没有精心设计和较低级别戒备森严的地方部队,它是在较低的水平非常糟糕的做法,但作为最后的手段是做(在我心中)不仅是可以接受,但往往是正确的事情。

当我看见

catch (Exception ex)

我的手开始摸索着锤子。 几乎没有任何借口可以捕获基础异常。 只有我想到的有效案例是:
1)第三方组件抛出异常(该死的作者)
2)非常顶级的异常处理(作为最后的手段)(例如处理WinForms应用程序中的“未处理”异常)

如果您发现可能发生许多不同类型的异常的情况,那么这是设计糟糕的好兆头。

我不同意Armin Ronacher。 如果引发StackOverflow异常,您会如何表现? 尝试执行其他操作可能会导致更糟糕的后果。 仅在您能够以有意义且安全的方式处理异常时才捕获异常。 捕获System.Exception以涵盖可能的异常范围是非常错误的。 即使你重新投掷它。

在代码中的最高级别捕获异常是完全合理的。 捕获基础异常类型很好,只要您不需要根据异常类型执行任何不同的逻辑。

此外,请确保您显示友好的常规错误消息,而不是显示实际的异常消息。 这可能会导致安全漏洞。

从某种意义上说,你不应该在任何地方都这样做是不好的做法。

在这种情况下,我认为这是唯一合理的解决方案,因为您的例外可能是真正的任何事情。 唯一可能的改进是在您捕获所有特定错误情况之前添加额外的处理程序,您可以对异常执行某些操作。

是的,可以在应用程序的顶层捕获基本Execption,这就是你正在做的事情。

您获得的强烈反应可能是因为在任何其他级别 ,捕获Base异常几乎总是错误的。 特别是在一个库中,这将是非常糟糕的做法。

如果你重新提出你无法正常处理的异常,这是完全可以的。 如果你只是捕获异常,你可以隐藏你不期望的代码中的错误。 如果您捕获异常以显示它们(并绕过die-and-print-traceback-to-stderr行为),这是完全可以接受的。

我认为海报是指这样的异常处理:

try {something} catch (SqlException) {do stuff} catch (Exception) {do other stuff}

这里的想法是你想首先捕获更具体的错误(比如SqlException)并适当地处理它们,而不是总是依赖于catch-all常规异常。

传统观点认为这是进行异常处理的正确方法(并且单独的Catch(Exception ex)很糟糕)。 实际上,这种方法并不总是有效,特别是当您使用其他人编写的组件和库时。

根据组件在开发环境中的行为方式,这些组件通常会在生产中抛出不同类型的异常,即使基础问题在两种环境中都相同。 这是ASP.NET中一个非常常见的问题,并且经常让我使用裸Catch(Exception ex)块,它不关心抛出什么类型的异常。

结构化异常处理在理论上是一个好主意。 在实践中,它仍然是您控制的代码域中的一个好主意。 一旦你介绍第三方的东西,它有时不能很好地工作。

我们使用Catch ex作为Exception(VB.Net变体)相当多。 我们记录它,并定期检查我们的日志。 追查原因,并解决。

我想抓住EX为例外是完全acceptabile 一旦你正在处理的生产代码,你必须妥善地处理未知异常的通用方法。 就个人而言,在完成模块/新功能之前,我没有把通用捕获,并对我在测试中发现的任何异常进行专门处理。 这似乎是两个世界中最好的。

没有; 在这种情况下,如果你不想停止程序,那么你就无法做任何事情,只要你正确地记录而不是将它隐藏在希望咧嘴中,顶级就是正确的地方。

重要的是通过应用程序了解异常的路径,而不是随意抛出或捕获它们。 例如,如果您捕获的异常是Out-Of-Memory会怎样? 你确定在那种情况下会显示你的对话框吗? 但是定义一个最后一个异常点并且说你永远不希望错误传播到那个点之前肯定是好的。

您应该捕获与您正在做的事情相关的例外情况。 如果你看一下你调用的方法,你会看到它们抛出的异常,并且你想要更加具体。 您应该有权知道您调用的方法可能抛出的异常,并适当地处理它们。

并且......比一次大尝试捕获更好,尝试并抓住你需要捕获的地方。

try {
   myThing.DoStuff();
}
catch (StuffGoneWrongException ex) {
   //figure out what you need to do or bail
}

也许不是这么紧密,但这取决于你在做什么。 请记住,这项工作不仅仅是编译它并将其放在某些桌面上,你想知道如果有什么东西会破坏什么以及如何修复它。 (在这里插入关于追踪的咆哮)

很多时候异常都被用来释放资源,如果(重新)抛出异常并不重要。 在这些情况下,你可以避免尝试捕获:

1)对于Disposable对象,您可以使用“using”关键字:using(SqlConnection conn = new SqlConnection(connStr)){// code}一旦超出使用范围(通常或通过return语句或异常),Dispsose方法在对象上自动调用。 换句话说,就像尝试/最终构建一样。

2)在asp.net中,您可以拦截Page对象的Error或UnLoad事件来释放您的资源。

我希望我帮助你!

我在回答“但是,暂停这个过程是最糟糕的结果......”

如果你可以通过运行不同的代码来处理异常(使用try / catch作为控制流),重试,等待和重试,使用不同但等效的技术重试(即回退方法),然后通过一切手段。

做错误消息替换和日志记录也很好,除非是伪礼貌 - 被动 - 积极“联系你的管理员”(当你知道没有管理员,如果管理员无法做任何事情!但是在你这样做之后,应用程序应该结束,即与未处理的异常相同的行为。

另一方面,如果您打算通过将用户返回到可能破坏其状态的代码线程来处理异常,我会说这比结束应用程序并让用户重新开始更糟糕 用户是否更好地必须在开始时重新启动或更好地让用户销毁数据?

如果我在模块中遇到意外的异常,确定哪些帐户可以从中提取资金,我是否真的想记录并报告异常并将用户返回到取款屏幕? 据我们所知,我们只是授予他从所有账户中提取资金的权利!

这很有助于捕获您可以处理的异常。 但有时也会发生由于环境不稳定或用户只是正确执行该过程,应用程序会遇到意外的异常。 您尚未在代码中列出或处理的内容。 有没有办法从app.config文件中捕获未处理的异常并显示常见错误?

还将详细信息异常消息放入日志文件中。

我一直在用异常工作,这是我目前正在遵循的实现结构:

  1. 在Try / Catch之外将所有内容变暗为Nothing / String.Empty / 0等。
  2. 将Try / Catch内的所有内容初始化为所需的值。
  3. 首先捕获最具体的异常,例如FormatException,但作为最后的手段保留在基本的异常处理中(你可以有多个catch块,请记住)
  4. 几乎总是抛出异常
  5. 让global.asax中的Application_Error sub正常处理错误,例如调用自定义函数将错误的详细信息记录到文件中并重定向到某个错误页面
  6. 杀死你在Finally块中变暗的所有对象

我认为最近不能“正确”处理异常是可接受的一个例子是使用通过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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM