【问题标题】:Catching generic non-fatal exceptions [closed]捕获通用的非致命异常[关闭]
【发布时间】:2014-01-07 02:21:49
【问题描述】:

传统观点认为我们应该只捕获我们期望的特定异常类型:

try
{           
    int.Parse(str); //I am aware of TryParse(), this is just for the sake of example
}
catch (FormatException ex)
{
    Console.WriteLine (ex);
}
catch (OverflowException ex)
{
    Console.WriteLine (ex);
}

但是,有时我们并不真正关心发生了哪个异常(只要它不是致命的),可能是因为我们只是想让用户知道发生了错误。在这些情况下,我们可以这样做:

try
{           
    Foo();
}
catch (Exception ex)
{
    if (IsCriticalException(ex))
    {
        Environment.FailFast("System Error", ex);
    }

    Console.WriteLine ("Error running Foo: {0}", ex);
}   

IsCriticalException 的实现方式与System.ClientUtils.IsCriticalException 类似。出于以下几个原因,我通常赞成这种方法:

  1. 有些方法可以抛出许多异常类型,捕获它们可能很麻烦。例如,File.Open 可以抛出九种不同类型的异常。
  2. 某些方法可能会引发未记录的异常。这要么是由于缺少文档,要么是由于某些错误。例如,ICommunicationObject.Close 实际上可以抛出 ArgumentException,这是由于一个模糊的错误。有些方法甚至不能静态地知道它们会抛出哪些异常,因为它们会动态加载其他模块/插件。假设他们可以用他们自己已知的异常来包装所有这些“外部”异常,但我相信并不是所有的都这样做。

这种方法的批评者认为方法的异常是其契约的一部分。如果抛出不属于本合约的异常,我们应该假设它的状态是损坏的。我们还将在该方法中发现一个错误(否则我们不会发现一个错误,因为我们已经吞下了意外的异常)。然后我们可以将此错误传递给框架的开发人员,这是一个胜利 - 特别是如果这些开发人员在我们公司,所以我们可以说是“自助”了。

我承认,批评者提出了正确的观点,但我觉得他们有点理想主义。实际上,我认为通用的非致命异常捕获在很多情况下都是有意义的。我说得有道理吗?

相关阅读:

【问题讨论】:

  • 你的 File.Open 例子是一个坏例子,IMO。从ArgumentException 派生的任何内容都指向您应该在首先调用File.Open 之前验证的内容。 PathTooLongExceptionDirectoryNotFoundExceptionFileNotFoundException 都派生自 IOException,并且可以使用单个 catch 块进行处理。只剩下三种类型需要担心:IOExceptionUnauthorizedAccessExceptionNotSupportedException 而不是九种。
  • 至于ICommunicationObject.Close,我个人的偏好是将ArgumentException 添加到要捕获的异常列表中(如果您知道它永远不应该被抛出,并且它只是因为错误而被抛出,并且该错误的影响使异常可以安全地忽略)。
  • @OhadSchneider 对我来说听起来很明智,我同意。这显然不是一刀切的方法。
  • @OhadSchneider "我为什么要检查字符串的长度、空格和无效字符?"一般来说,ArgumentException 和派生的异常意味着该方法告诉您“不要传递给我”,如果您仍然传递它,那么您就是代码有错误的人。我认为如果File.Open 会为无效的文件名字符抛出不同的异常可能会更好。
  • @close-voters 我认为这是一个合理的设计问题,我是从现实生活中出现的问题中提出的。如果您不同意,请发表评论。

标签: c# .net exception-handling


【解决方案1】:

传统观点认为我们应该只捕获我们期望的特定异常类型

实际上,我认为您应该准确捕获那些您可以处理的异常。捕获异常只是为了重新抛出它们是没有用的,让那些你可以治愈的异常通过也是没有意义的。

在你上面的例子中,我认为有一个包罗万象的块会很好,毕竟不转换该字符串是一个可恢复的错误,无论弹出什么异常(OutOfMemoryException 除外,它无论如何都无法处理,因为任何尝试处理会使用内存)。

【讨论】:

  • 在包含fault 块的语言中,我同意应该只捕获希望解决的异常。如果方法希望将对象置于临时无效状态,然后重新建立其不变量,则在对象状态无效时可能发生的任何意外异常都应明确使对象无效,即使它没有希望处理异常.不幸的是,C# 确实没有提供太多的替代方法来捕捉和重新抛出。
猜你喜欢
  • 2014-08-26
  • 2019-01-13
  • 2019-01-05
  • 2013-07-07
  • 2012-02-08
  • 1970-01-01
  • 2015-06-10
  • 2015-06-20
相关资源
最近更新 更多