捕获异常,记录并再次抛出异常是一种好做法吗?

本文关键字:一种 记录 抛出异常 捕获异常 | 更新日期: 2023-09-27 18:05:58

出于日志记录的目的,我想捕获一个异常。但是由于我还需要抛出异常,因此我将再次抛出异常。例如,我将在c#中这样做:

try
{
    //exception-prone code block here
}
catch(Exception ex)
{
   Logger.Log(ex);
   throw new Exception(ex);
}

现在我很好奇这是日志记录的最佳方式吗?请建议。

捕获异常,记录并再次抛出异常是一种好做法吗?

没有最好的日志记录方式。它总是取决于你需要什么。

但是,如果你想减少代码,只是记录错误,你可以创建自己的事件处理程序,并将其附加到特定的事件。

以AppDomain为例。UnhandledException事件:

MSDN中的演示代码:

public class Example 
{
   [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlAppDomain)]
   public static void Main()
   {
      AppDomain currentDomain = AppDomain.CurrentDomain;
      currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
      try {
         throw new Exception("1");
      } catch (Exception e) {
         Console.WriteLine("Catch clause caught : {0} 'n", e.Message);
      }
          throw new Exception("2");
       }
       static void MyHandler(object sender, UnhandledExceptionEventArgs args) 
       {
          Exception e = (Exception) args.ExceptionObject;
          Console.WriteLine("MyHandler caught : " + e.Message);
          Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
       }
    }
}

你可以把你的登录放在MyHandler方法中,然后完成它。如果没有真正处理异常,就不需要滥用catch块。

在Asp。. Net中可以覆盖global.asax:

中的Application_Error方法。
protected void Application_Error()
{
    Exception ex = Server.GetLastError();
    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    logger.Fatal(ex);
}

根据您的日志程序,现在可以做任何事情。在我上面的例子中,每个致命的异常都通过电子邮件发送到事件管理系统。

在我看来,关键是,try / catch应该处理异常。在catch块中记录错误就像在catch块中根本没有语句,您只是吞下异常,而不处理它。最后只是多余的代码。

这个答案更多是关于错误处理的最佳实践,而不是记录异常的最佳实践

异常处理是一个代价昂贵的过程,它会故意破坏程序的正确流程,因此不应该用作默认的检查机制,而应该始终是验证检查。例如,如果你想创建一个文件,在创建它之前检查该文件是否存在,这允许程序的正常流程处理预期的情况。

异常处理应该只在异常情况下使用,正如其名称所暗示的那样。要么是异常出乎意料,要么是在没有进一步信息的情况下无法决定如何处理异常。例如,在上面的MS框架给你一个函数来检查文件是否存在,但是如果文件创建被调用并且文件已经存在,它应该怎么做?追加到现有文件?删除它并创建一个新的??用不同的文件名再试一次?微软不知道什么是正确的方法来处理这个问题,所以不得不提出一个异常,让你知道你做了一些你不应该做的事情。因此,这是您应该在代码中引发异常的唯一时间。

如果你正在处理一个异常,那么这正是你应该做的,处理它。你永远不需要在异常处理程序中抛出异常,除非你正在开发类库,在这种情况下,库不适合与用户通信,在这种情况下,异常应该不被处理,或者用额外的信息重新抛出。如果你不能在代码中处理异常,那么你的异常处理程序就在错误的地方。

异常处理程序应该做以下三件事中的一件

  1. 执行纠正错误的预定义操作如等待5秒再试一次
  2. 询问用户哪个预定义动作是解决错误的正确方法ie重试或取消
  3. 向用户报告错误并将程序返回到稳定状态状态
  4. 当前无法保存文件,请稍后再试。

这些操作中的任何一个都可以包括异常的日志记录,但它们都应该是最终的

try
{
    //exception-prone code block here
}
catch(KnowException1 ex)
{
   Logger.Log(ex); //logging may be optional as its a known handled situation
   //perform predefined action
}
catch(KnowException2 ex)
{
   Logger.Log(ex); //logging may be optional as its a known handled situation
   // fire message box asking users how to proceed
   //perform selected predefined action
}
catch(UnknowException ex)
{
   Logger.Log(ex); //logging is vital
   // fire message box something unexpected happened
   //cancel action and return to normal operations
}

这就是为什么总是建议抛出一个适当类型的异常

出于日志记录的目的,我想捕获一个异常

不再是首选选项。

在c# 6.0的新特性(叫做异常过滤器)中,你有特殊的方式来记录异常

private static bool Log(Exception e) { /* log it */ ; return false; }
…
try { … } catch (Exception e) when (Log(e)) {}

建议这样做,因为您不需要重新抛出

定义和维护自定义异常存储将增强支持体验,并使维护工程师的工作更加轻松。

请参考MSDN强烈推荐的自定义异常指南

https://msdn.microsoft.com/en-us/library/vstudio/ms229064 (v = vs.100) . aspx

例如,假设您正在销售一个带有您的软件的杀手级家用电器。拥有自定义异常将使维护人员更容易了解设备的问题所在,并节省一些宝贵的调试时间。