try/catch vs AppDomain.UnhandledException 来记录和崩溃应用程序

本文关键字:记录 崩溃 应用程序 UnhandledException catch vs AppDomain try | 更新日期: 2023-09-27 17:57:03

我所知,你应该只在实际处理异常时使用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??                
    }
}

有多种情况可被视为异常/不需要的行为,例如:

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

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

try/catch vs AppDomain.UnhandledException 来记录和崩溃应用程序

代码中加入 try/catch 语句只是为了让应用程序崩溃是没有生产力的。 CLR 已经为您处理了这个问题。 而且你有AppDomain.UnhandledException来生成体面的信息来诊断原因。

只有在您必须清理某些东西的非常特殊的情况下,例如您不想继续放置的文件,您才应该考虑编写 try/catch。 这本身就是一个非常不稳定的要求,不能保证您的 catch 块会执行。 当异常像StackOverflowException或ExecutionEngineException一样令人讨厌时,它不会。 或者程序不会自行清理的更常见原因,有人绊倒电源线或从任务管理器终止进程。

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

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

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

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

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

SQL 异常通常可以自然冒泡,因为它们包含不错的错误信息(例如 "undeclared variable '@arg'"

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

  1. 仅当您计划处理异常时,才捕获异常。
  2. 过度使用 try/catch 会导致异常吞噬和/或丢失有价值的堆栈跟踪信息,并可能导致可维护性问题(如果您决定标准化错误/日志记录怎么办? 而是使用 try/finally 或使用块来实现清理。
  3. 通过全局异常处理程序在边界处捕获异常。
  4. 使用 AppDomain.UnhandledException 来了解名称所暗示的内容:记录未经处理的异常。 如果不记录这些内容,则只会在日志查看器中找到CLR"Windows错误报告"条目和一些对您实际上没有用的转储文件。 利用 AppDomain.UnhandledException 总是一个好主意,这样如果你的应用程序崩溃了,你就知道为什么了。

请务必注意,"处理"异常并不一定意味着清理或追溯逻辑。 处理可能只是意味着将错误格式化为更用户友好的格式,或者隐藏您不希望任何人看到的敏感堆栈跟踪。 我经常记录一个详细的错误并返回一个格式化的错误。

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

良好的异常管理经验法则

了解和使用异常