关于c#:捕获System.Exception总是一个坏习惯吗?

Is it always a bad practice to catch System.Exception?

请考虑以下代码,它抛出了三个不同的异常(即System.Configuration.ConfigurationErrorsExceptionSystem.FormatExceptionSystem.OverflowException

1
int SomeInt = Convert.ToInt32(ConfigurationManager.AppSettings["SomeIntValue"]);

异常是不同的,因此在实践中,我应该有三个不同的catch块来处理每个特定的异常。但是,在这种特殊情况下,所有异常都以相同的方式处理:将日志写入,例如,eventviewer,并显示一条通知配置错误的消息…在这个特殊的原因中,使用是否太差?

1
2
3
4
5
6
7
8
try
{
    int SomeInt = ConfigurationManager.AppSettings["SomeIntValue"];
}
catch (Exception ThisException)
{
    /* Log and display error message. */
}

还是应该使用三个catch块,在每个块中重复代码?


有关此问题的讨论,请参阅C异常处理失败。

简而言之,如果捕获了一般异常,那么应该检查它是否是预期的类型之一,如果不重新引发它。

更新(有点超出范围)

还有几次,我认为做一次全力以赴是有效的。这是非常罕见的,但有时在WebServices中,或者在ASP.NET中的后台线程上执行某些操作时,作为异常情况,会重新启动整个应用程序,如果您依赖它,人们可能会丢失会话。


捕获System.Exception是不好的做法。…或者更好的是,除了应用程序的顶级之外,在任何地方处理System.Exception都是不好的做法。你应该做的是:

  • 捕获系统。异常
  • 测试您计划以相同方式处理的类型的异常
  • 如果不是这样的话,就再告诉我一次。
  • 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    catch (Exception ex)
    {
        if (ex is FormatException || ex is OverflowException || ex is ConfigurationErrorsException) {
            CommonHandler();
        }
        else {
            throw;
        }
    }


    我不认为这是坏做法。如果您想要的功能是"每当这段代码抛出异常时,就执行这些操作",那么我认为捕获System.Exception是完全合适的。

    事实上,您包装的是一个非常具体的框架函数,而不是一大块自定义代码,这在我看来也有帮助。


    真正需要的是,但是.NET异常层次结构没有提供一种清晰的方法来区分异常,这意味着"请求的操作没有发生,但是系统状态基本上是良好的,除非操作没有发生"所暗示的程度与"CPU着火,甚至试图保存CU"的程度不同。当前用户的工作可能不会使事情变得更糟。"在很多情况下,人们确实应该努力捕获第一种类型的所有异常,而理想情况下不捕获第二种类型的异常。虽然在上述两个级别之外有一些级别,但通常在捕获异常时,人们并不真正关心InvalidArgumentException或InvalidOperationException之间的区别;我们关心的是整个系统状态是有效的还是损坏的。

    事实上,如果一个人正在调用文件导入插件,并抛出一个异常,我不确定他是否可以这样做,除非尝试捕获并重新引发真正糟糕的异常,同时让所有其他异常显示一个"无法打开此文件"对话框。希望系统在那一点上的状态本质上就像用户没有试图打开文件一样,但是没有某种标准化的方式来表示异常的严重性,我认为没有任何方法可以确定。

    顺便说一下,如果我有自己的druchers,会有一个类exceptionbase,所有的异常都会从中派生;大多数异常都会从异常派生(反过来又从exceptionbase派生),但是像threadabortexception、stackoverflowexception、outofmemoryexception等东西都会从criticalexception派生。这样就可以捕捉到大多数"意外"的异常,而不会意外地扼杀真正糟糕的异常。


    在这种特定的情况下,完全可以使用不同的catch块,因为您可以根据获得的异常情况采取不同的操作。

    对于前两个,您可以静默地设置一个合理的默认值,以避免不必要地干扰用户,然后希望在保存文件时问题自行解决,对于后一个异常,您可以询问用户是否希望继续加载过程(在这种情况下,您设置了一个合理的默认值),因为配置文件显然已损坏。PTD。

    一般来说,我的想法是:对于被抛出的不同类型的异常,我需要采取不同的行动吗?通常情况下,答案是否定的,所以一个空白的catch(Exception ex){ /* log... */ }(或者甚至没有catch,如果异常总是致命的话)就足够了。

    编辑:空白与空白检查一样,不是空块:)


    这不一定是坏的做法,坏的做法通常发生在你做愚蠢的事情,在捕捉块。捕获基本异常类是一种很好的安全措施,假定在发生错误时需要做一些事情。捕获特定异常类的情况是最好的清单,当该特定类向您提供可以执行操作的信息时,例如,捕获sqlException可以帮助您查看特定于该类的某些属性,并让您处理该问题。

    通常情况下,人们会捕捉到一个异常并做一些愚蠢的事情,比如创建一个新的异常,或者更糟的是,吞下异常的细节。

    一个经常被忽略的模式是你可以捕捉,重新表演。

    1
    2
    3
    4
    5
    catch(Exception ex)
    {
     //do something
     throw;
    }

    从而保留异常细节。