try / catch vs AppDomain.UnhandledException to log&使应用程序崩溃

时间:2013-01-31 14:22:58

标签: c# .net exception-handling try-catch

据我所知,你应该只在实际处理异常时才使用try / catch,而不仅仅是报告和记录它然后使应用程序崩溃。否则,最好只检查有意义的不同场景(例如,如果sth == null),或者 - 如果您的目的只是记录异常并使应用程序崩溃 - 使用AppDomain.UnhandledException。但情况总是这样吗?为什么?

假设以下方法接受一个数组并在执行一些数据库和文件系统操作后返回MemoryStream。

MemoryStream Read (int[] IDs)
{
    try
    {
        using (SqlConnection connection = new SqlConnection(connection_string))
        {
            connection.Open();    

                        // a bunch of code executing SQL queries & constructing MemoryStream, which is returned at the end of the block
        }
    }
    catch (Exception e)
    {
        // report the exception to the user & log it
        throw; // pointles??                
    }
}

有多种情况可以被视为特殊/不受欢迎的行为,例如:

  • 参数(IDs [])为null,
  • 无法建立SQL连接,
  • 无法执行特定的SQL查询。

所有这些情况都被认为是例外情况,如果您只想记录异常(然后崩溃)可能是不好的做法,仍然将所有内容放在try / catch中 - 但为什么呢?在上述情况下,最佳处理行为是什么?完全避免try / catch,使用if语句检查空引用(在这种情况下返回null)并使用AppDomain.UnhandledException记录其他所有内容?使用try / catch,但仍然使用if语句检查空引用(在这种情况下返回)?还有别的吗?

3 个答案:

答案 0 :(得分:2)

仅使用try / catch语句来编写代码以使应用程序崩溃是没有效率的。 CLR已经为您解决了这个问题。而且你有AppDomain.UnhandledException来生成正确的信息来诊断原因。

只有在您 清理某些内容的非常具体的情况下,如果您考虑编写try / catch,请说一个您不想继续放置的文件。这本身就是一个非常不确定的要求,不能保证你的catch块会执行。当异常像StackOverflowException或ExecutionEngineException一样令人讨厌时,它不会。或者更常见的原因是程序没有自行清理,有人绊倒电源线或从任务管理器中删除进程。

答案 1 :(得分:1)

  

你应该只在实际处理异常时才使用try / catch而不仅仅是报告&记录它然后崩溃应用程序

我同意第一部分,但我想补充一点,当你可能无法控制调用层时,在层边界添加日志记录是很有价值的。例如我在顶部方法中记录Web服务中发生的所有异常,以确保我已登录服务器,因为调试信息(堆栈跟踪等)并不总是优雅地跨通信层

在您的特定示例中,我会检查"例外"条件你可以,但让其他例外发生"自然"。对于您的具体示例:

  
      
  • 参数(IDs [])为null,
  •   
  • 无法建立SQL连接,
  •   
  • 无法执行特定的SQL查询。
  •   

对于第一个,我会检查null个参数的原因有一个:NullReferenceException为您提供 no 关于异常原因的上下文,其他发生的地方。我更喜欢检查null,然后抛出一个新的ArgumentNullException异常,因为你可以添加哪个参数为null。您可能仍需要进行一些挖掘以找出为什么它为null,但它可以节省您大量的调试时间。

SQL异常通常会自然冒出来,因为它们中包含了不错的错误信息(例如"undeclared variable '@arg'"

答案 2 :(得分:1)

我最近开始自己阅读这个主题。我的基本理解是:

  1. 如果您打算处理它,只能捕获异常。
  2. 过度使用try / catch会导致异常吞咽和/或丢失有价值的堆栈跟踪信息,并可能导致可维护性问题(如果您决定标准化错误/日志记录,该怎么办?)。而是使用try / finally或使用块来实现清理。
  3. 通过全局异常处理程序捕获边界处的异常。
  4. 使用AppDomain.UnhandledException来确切地暗示名称:记录未处理的异常。如果你不记录它们,你只会在日志查看器中找到一个CLR“Windows错误报告”条目和一些对你毫无用处的转储文件。利用AppDomain.UnhandledException总是一个好主意,所以如果你的应用程序崩溃了,你知道原因。
  5. 重要的是要注意“处理”异常并不一定意味着清理或追溯逻辑。处理可能只是意味着将错误格式化为更加用户友好的内容,或者隐藏您不希望任何人看到的敏感堆栈跟踪。我经常记录一个详细的错误并返回一个格式化的错误。

    同样,这正是我最初收集的内容。以下是一些消息来源:

    Good Exception Management Rules of Thumb

    Understanding and Using Exceptions