【问题标题】:Ways to handle exception处理异常的方法
【发布时间】:2012-07-25 21:11:35
【问题描述】:

除了记录之外,还有什么是处理异常?我问人们说只捕获你可以处理的异常。

例如,我编写了一个与 Active Directory 交互的工具。我在域控制器上运行它。由于我对 AD 有深入的了解,因此我可以处理其他例外情况(例如,我可以提出要求另一个域名的提示)并从那里开始。但是,如果生产服务器上的域出现问题如此严重,这不是例外吗?

所以在这种情况下,环境问题应该是异常的(假设是生产和 AD 等),但这是我可以处理的。我认为处理异常取决于节目观众(同意)?

无论如何,主要问题:要推断我是否可以“处理”异常,我需要知道处理需要什么 - 除了记录并向用户提供另一种选择(在这种情况下,我通过使用 if file exists 来避免异常等)。

对于上述情况(AD),我的代码结构如下:

if (adIsAvailable)
  // do whatever here

else
  raise exception and ask for action

然后在 gui 中捕获它

对该设计的有效性有什么想法吗?

【问题讨论】:

  • 如果!adIsAvailable 意味着它甚至无法找到域服务器,我会称之为异常情况。如果它找不到您正在寻找的搜索片段,我不会称之为例外。

标签: c# exception exception-handling


【解决方案1】:

很好的问题。 请记住,您只能处理特定类型的异常,并将真正关键的异常传播到堆栈中并被遗忘。

异常处理的一种用法是与用户交互,当然,正如您所说,最好的方法是检查一个前提条件,如果违反(文件不存在)将抛出异常,而不是执行实际任务并依赖异常机制进行通知。

异常处理的另一种用法是重试。例如,您正在向 DB 发送查询并收到 TimeOutException 或另一个指示连接暂时不可用的错误。在这种情况下,您可能需要稍等片刻,然后再试一次。并且仅当您在 3 次之后未能到达 Db 时 - 将异常传播到上层。

处理异常的另一种方法是向异常添加数据或更改其类型。 您可能希望捕获 TimeOutException 但抛出 MyApplicationException,其中包含例如您尝试执行的 SQL(原始异常是内部异常)。

此外,您可能想要做相反的事情 - 从异常中删除数据,例如堆栈跟踪,这是出于安全原因(将应用程序的内部工作暴露给恶意用户是不明智的)

顺便说一下,在您的情况下,您可能希望格式化用户友好的消息,清楚地说明问题的性质,而不是向用户显示堆栈跟踪和晦涩的消息。这是可以在异常处理期间完成的转换的另一个示例。

不久前,我的应用程序抛出了一个异常,该异常是由于 DML 操作中的表空间空间不足而引起的。用户遇到了一个带有错误代码的可怕异常。我所做的是添加一个处理程序,该处理程序检查从命令调用引发的异常,并为此错误代码添加特殊处理 - 它现在可以告诉用户确切的问题是什么!

【讨论】:

  • fyi 自动重试,请谨慎行事。 blogs.msdn.com/b/oldnewthing/archive/2005/11/07/489807.aspx
  • @asawyer 我完全同意,重试应该谨慎使用,最好是在应用程序的最低级别。例如执行 DbCommand。
  • 很好的答案,由于之前评论中发布的链接,我不认为重试是一种机制。不过,在某些情况下重试可能是可行的。为了构造代码,我可以在循环中尝试一个操作,如果成功则退出,如果重试尝试 = 3,则在循环中进行检查,如果是,则抛出异常。
【解决方案2】:

这里有几个不同的问题。

  1. 如何处理(并决定何时处理)底层代码抛出的异常
  2. 何时自己抛出异常
  3. 生产代码是否应与开发代码不同地处理“异常”情况。代码。

关于第(1)点:

这可能有点混乱且难以决定 - 不同的 API 可能使用不同的异常,即使在同一种语言中也是如此。

例如,在 C# 中,我更喜欢使用 int.TryParse() 而不是 int.Parse() 并捕获 FormatException,如果我希望我的输入可能无法解析,并且我想编写代码来处理这种情况。

如果我不想处理错误输入,我将使用int.Parse(),并让异常传播。

这取决于情况,唉。

关于第(2)点:

例外基本上意味着“我放弃”。他们的意思是出了点问题,但你不会在那里自己处理。

关于第(3)点:

我认为这几乎总是一个坏主意。

旁白:

我不同意Vitality's answer 的部分内容,它说:

最好的方法是检查一个前提条件,如果违反(文件确实 不存在)会抛出异常,而不是执行实际的 任务并依赖异常机制进行通知。

如果你写这样的代码:

if (file_exists(x))
{ /* do something */ }
else
{ /* whatever */ }

然后你就可以接受比赛条件了。 也许文件在file_exists() 检查之间被删除了,所以你的代码无论如何都会抛出异常。

或者该文件可能是在您进入 else 部分之后创建的。

在这种情况下,我认为最好做你想做的事情,如果出现问题,处理异常。

【讨论】:

  • 但是对于文件打开的例子,你会用 try-catch 来捕捉竞争条件然后处理它?不过,这是一个经典的例子。
  • @dotnetdev:使用 try-catch,没有竞争条件,也不需要提前检查任何东西。文件要么成功打开,要么由于某种原因失败(例如FileNotFoundException,或者可能是UnauthorizedAccessException,等等)。不过,也许我不明白你的评论......
猜你喜欢
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 2012-12-27
  • 2015-05-21
  • 2018-08-19
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多