C# 捕获异常、记录并再次抛出异常是一种好的做法吗?

C# 捕获异常、记录并再次抛出异常是一种好的做法吗?,c#,exception-handling,C#,Exception Handling,为了记录日志,我想捕获一个异常。但是因为我还需要抛出异常,所以我会再次抛出异常。例如,我会在C#中这样做,如下所示: try { //exception-prone code block here } catch(Exception ex) { Logger.Log(ex); throw new Exception(ex); } 现在我很好奇,这是记录日志的最佳方式吗?请给我一些建议 为了记录日志,我想捕获一个异常 这不再是首选方案 有了新功能(称为异常过滤器),您就有了记

为了记录日志,我想捕获一个异常。但是因为我还需要抛出异常,所以我会再次抛出异常。例如,我会在C#中这样做,如下所示:

try
{
    //exception-prone code block here
}
catch(Exception ex)
{
   Logger.Log(ex);
   throw new Exception(ex);
}
现在我很好奇,这是记录日志的最佳方式吗?请给我一些建议

为了记录日志,我想捕获一个异常

这不再是首选方案

有了新功能(称为异常过滤器),您就有了记录异常的特殊方法

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

建议使用这种方式,因为您不必重新抛出。

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

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

以事件为例:

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);
       }
    }
}
您可以将您的loggin放入MyHandler方法中并完成它。如果不真正处理异常,就不需要滥用catch块

在Asp.Net中,您可以覆盖global.asax中的应用程序错误方法:

protected void Application_Error()
{
    Exception ex = Server.GetLastError();
    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
    logger.Fatal(ex);
}
根据您的日志记录例程,现在可以执行任何操作。在我上面的例子中,每个致命的异常都会通过电子邮件发送到事件管理系统


在我的观点中,关键点是,
try/catch
应该处理异常。在catch块中记录错误就像在catch块中根本没有语句一样,您只是吞咽了异常,而没有处理它。最后它只是冗余代码。

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

private static bool Log(Exception e) { /* log it */ ; return false; }
…
try { … } catch (Exception e) when (Log(e)) {}
异常处理是一个昂贵的过程,它会故意中断程序的正确流程,因此不应将其用作默认检查机制,而应始终进行验证检查。例如,如果要创建文件,请在创建之前检查该文件是否存在,这样,程序的正常流程就可以处理预期的情况

异常处理只应在异常情况下使用其名称。当异常不是预期的情况时,或者在没有进一步信息的情况下,您不可能决定如何处理异常。 例如,在上面的示例中,MS框架为您提供了一个检查文件是否存在的函数,但是如果调用了文件创建,并且文件已经存在,那么它应该做什么?是否附加到现有文件?删除它并创建一个新的??是否使用其他文件名重试?Microsoft不知道如何正确处理此问题,因此必须引发异常,让您知道您做了不该做的事情。因此,这是您在代码中引发异常的唯一时间

如果你正在处理一个异常,那么这正是你应该做的,处理它你永远不需要在异常处理程序中抛出一个异常,除非你正在开发类库,在这种情况下,类库不适合与用户通信,在这种情况下,应不处理异常,或使用其他信息重新处理异常。如果无法在代码中处理异常,则异常处理程序位于错误的位置

异常处理程序应执行以下三项操作之一

  • 执行纠正错误的预定义操作 请等5秒钟再试一次
  • 询问用户哪种预定义操作是解决错误的正确方法 请重试或取消
  • 向用户报告错误并将程序返回到稳定状态 状态 ie此时无法保存文件,因为诸如此类,请稍后再试
  • 这些操作中的任何一个都可以包括异常的日志记录,但它们都应该是最终的

    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
    }
    

    这就是为什么提出适当类型的异常总是明智的

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

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


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

    值得注意的是,如果像这样抛出,您将丢失堆栈跟踪。只需使用
    throwAppDomain.UnhandledException
    事件、WinForms/WPF和Asp.Net中的
    ApplicationOn_Error
    。异常处理代价高昂,会中断程序流程,因为只有在没有其他选择时才应使用此类异常处理。也就是说,在执行某个操作之前,不可能检查该操作是否会成功,或者在没有用户输入的情况下,不可能处理出了什么问题。因此,所有异常处理都应该在尽可能小的微型ie上进行。异常处理程序不应该引发异常,最糟糕的情况是记录异常,并通知用户发生错误。Seems C#6.0将使异常处理变得容易得多。现在我已经达到了.NET4.5。会热情地等待!:)。Net版本与C#编译器无关。您可以编译4.5版,同时使用异常过滤器(假设您使用的是最新的VS 2015+),VS2015已经过时了。试试看,C#6.0太酷了,一天都不能没有它。开发人员不一定会选择它,通常会有bud