捕获异常,记录并再次抛出异常是一种好做法吗?
本文关键字:一种 记录 抛出异常 捕获异常 | 更新日期: 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框架给你一个函数来检查文件是否存在,但是如果文件创建被调用并且文件已经存在,它应该怎么做?追加到现有文件?删除它并创建一个新的??用不同的文件名再试一次?微软不知道什么是正确的方法来处理这个问题,所以不得不提出一个异常,让你知道你做了一些你不应该做的事情。因此,这是您应该在代码中引发异常的唯一时间。
如果你正在处理一个异常,那么这正是你应该做的,处理它。你永远不需要在异常处理程序中抛出异常,除非你正在开发类库,在这种情况下,库不适合与用户通信,在这种情况下,异常应该不被处理,或者用额外的信息重新抛出。如果你不能在代码中处理异常,那么你的异常处理程序就在错误的地方。
异常处理程序应该做以下三件事中的一件
- 执行纠正错误的预定义操作如等待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
}
这就是为什么总是建议抛出一个适当类型的异常
出于日志记录的目的,我想捕获一个异常
不再是首选选项。
在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
例如,假设您正在销售一个带有您的软件的杀手级家用电器。拥有自定义异常将使维护人员更容易了解设备的问题所在,并节省一些宝贵的调试时间。