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

时间:2015-08-03 08:41:34

标签: c# exception-handling

出于记录的目的,我想抓住一个例外。但是因为我还需要抛出异常,然后我会再次抛出异常。例如,我会在C#中执行此操作,如下所示:

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

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

4 个答案:

答案 0 :(得分:3)

没有最好的记录方式。它总是取决于你需要的东西。

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

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块中有一个no语句一样,你只是吞下异常而不处理它。最后它只是冗余代码。

答案 1 :(得分:2)

  

出于记录的目的,我想捕捉异常

它不再是首选。

使用新的C# 6.0功能(称为异常过滤器),您可以使用特殊方式记录异常

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

建议采用这种方式,因为您不必重新投掷。

答案 2 :(得分:2)

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

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

只有在特殊情况下才能使用

异常处理。当异常是不期望的事情或者你不可能决定如何处理异常而没有进一步的信息时。 例如,在上面,MS框架为您提供了检查文件是否存在的功能,但是如果调用了文件创建并且文件已经存在,它应该做什么?附加到现有文件?删除它并创建一个新的?再试一次不同的文件名?微软无法知道处理这个问题的正确方法是什么,所以必须提出异常才能让你知道你做了一些你不应该做的事情。因此,这是您应该在代码中引发异常的唯一时间。

如果您正在处理异常,那么这正是您应该做的事情,处理它您永远不需要在异常处理程序中抛出异常,除非您正在开发类库,在这种情况下isn'适合于库与用户进行通信,在这种情况下,异常应该保持未处理状态或重新增加其他信息。如果你不能在代码中处理异常,那么你的异常处理程序就在错误的位置。

异常处理程序应该做3件事之一

  1. 执行纠正错误的预定义操作     即等待5秒再试一次
  2. 询问用户哪种预定义操作是解决错误的正确方法     即重试或取消
  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
    }
    

    这就是为什么总是建议引发适当类型的异常

答案 3 :(得分:1)

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

请参阅MSDN强烈建议的自定义例外指南。

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

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