C# 我是否应该捕获异常以记录它们?
我应该捕获用于日志记录的异常吗 public foo(..) { try { ... } catch (Exception ex) { Logger.Error(ex); throw; } } 公共食品(……) { 尝试 { ... }捕获(例外情况除外){ 记录器错误(ex); 投掷; } } 如果在我的每一层(DataAccess、Business和WebService)中都有这样的功能,这意味着会记录多次异常 如果我的层在单独的项目中,并且只有公共接口中有try/catch,那么这样做有意义吗?C# 我是否应该捕获异常以记录它们?,c#,logging,exception-handling,C#,Logging,Exception Handling,我应该捕获用于日志记录的异常吗 public foo(..) { try { ... } catch (Exception ex) { Logger.Error(ex); throw; } } 公共食品(……) { 尝试 { ... }捕获(例外情况除外){ 记录器错误(ex); 投掷; } } 如果在我的每一层(DataAccess、Business和WebService)中都有这样的功能,这意味着会记录多次异常 如果我的层在单独的项目中,
为什么?为什么不呢?我可以使用其他方法吗?绝对不行。您应该找到处理异常的正确位置(实际执行一些操作,例如catch而不是rethrow),然后记录它。当然,您可以而且应该包括整个堆栈跟踪,但是按照您的建议会在代码中添加try-catch块。除非您要更改异常,否则您应该只在要处理错误的级别上进行日志记录,而不是重新发送错误。否则,您的日志只会有一堆“噪音”,每层记录3条或更多相同的消息 我的最佳做法是:
使用您自己的异常来包装内置异常。通过这种方式,您可以在捕获异常时区分已知错误和未知错误。如果您有一个方法调用其他方法,这些方法可能会抛出异常以对预期和意外故障做出反应,那么这是非常有用的。如果您需要记录所有异常,那么这是一个非常好的主意。也就是说,没有其他原因记录所有异常不是一个好主意。您可能希望在最高级别上进行记录,这通常是您的UI或web服务代码。多次记录日志是一种浪费。此外,当您查看日志时,您希望了解整个故事
在我们的一个应用程序中,我们的所有页面都派生自一个BasePage对象,这个对象处理异常处理和错误日志记录。如果这是它唯一做的事情,我认为最好从这些类中删除try/catch,并将异常引发到负责处理它们的类。这样,每个异常只会得到一个日志,从而提供更多清晰的日志,甚至您也可以记录stacktrace,这样您就不会错过异常发生的位置。您可能希望查找标准异常处理样式,但我的理解是:在可以为异常添加额外细节的级别上处理异常,或者在您将向用户显示异常的级别 在您的示例中,除了捕获异常、记录异常并再次抛出异常,您什么也不做。。如果您所做的只是记录它,为什么不在最高级别用一次try/catch而不是在每个方法中捕获它呢
如果您打算在再次抛出异常之前向异常添加一些有用的信息,我只会在该层处理它-将异常包装在您创建的新异常中,该异常包含除低级异常文本之外的有用信息,这通常对没有上下文的任何人都没有什么意义。我的方法是记录异常仅在处理程序中。可以说是“真正的”处理者。否则,日志将很难读取,并且代码的结构也会变差 这取决于例外情况:如果这真的不应该发生,我肯定会记录它。另一方面:如果您期望出现这种异常,那么您应该考虑应用程序的设计 无论哪种方式:您至少应该尝试指定要重新刷新、捕获或记录的异常
public foo(..)
{
try
{
...
}
catch (NullReferenceException ex) {
DoSmth(e);
}
catch (ArgumentExcetion ex) {
DoSmth(e);
}
catch (Exception ex) {
DoSmth(e);
}
}
最好的做法是翻译例外情况。不要只是记录它们。如果要知道引发异常的特定原因,请引发特定异常:
public void connect() throws ConnectionException {
try {
File conf = new File("blabla");
...
} catch (FileNotFoundException ex) {
LOGGER.error("log message", ex);
throw new ConnectionException("The configuration file was not found", ex);
}
}
您将希望在层边界处登录。例如,如果您的业务层可以部署在n层应用程序中物理上独立的计算机上,那么以这种方式记录并抛出错误是有意义的 通过这种方式,您可以在服务器上记录异常,而不需要在客户端机器上查找发生了什么
我在使用远程处理或ASMXWeb服务的应用程序的业务层中使用此模式。使用WCF,您可以使用附加到ChannelDispatcher的IErrorHandler(完全是另一个主题)截获并记录异常,因此您不需要try/catch/throw模式。一般的经验法则是,只有在您确实可以对异常采取措施的情况下,您才能捕获异常。因此,在业务层或数据层,您只能在如下情况下捕获异常:
try
{
this.Persist(trans);
}
catch(Exception ex)
{
trans.Rollback();
throw ex;
}
我的业务/数据层尝试保存数据-如果生成异常,则回滚所有事务并将异常发送到UI层
在UI层,您可以实现一个通用异常处理程序:
Application.ThreadException+=新的ThreadExceptionEventHandler(Application\u ThreadException)
然后处理所有异常。它可能会记录异常,然后显示用户友好的响应:
static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
LogException(e.Exception);
}
static void LogException(Exception ex)
{
YYYExceptionHandling.HandleException(ex,
YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
YYYExceptionHandling.ExceptionPriority.Medium,
"An error has occurred, please contact Administrator");
}
在实际的UI代码中,如果要执行不同的操作,例如显示不同的友好消息或修改屏幕等,则可以捕获单个异常
另外,作为提醒,请始终尝试处理错误(例如除以0),而不是抛出异常。您需要制定处理异常的策略。我不推荐捕猎和再捕杀。除了多余的日志条目外,它还使代码更难阅读。 考虑写入异常的构造函数中的日志。这将为要从中恢复的异常保留try/catch;使代码更易于阅读。要处理意外或不可恢复的异常,您可能需要尝试/捕获 catch (const Exception& ex) { ... }
public void methodWithDynamicallyGeneratedSQL() throws SQLException {
String sql = ...; // Generate some SQL
try {
... // Try running the query
}
catch (SQLException ex) {
// Don't bother to log the stack trace, that will
// be printed when the exception is handled for real
logger.error(ex.toString()+"For SQL: '"+sql+"'");
throw ex; // Handle the exception long after the SQL is gone
}
}