小编典典

如何使用 try catch 进行异常处理是最佳实践

all

在维护我同事的代码时,即使是自称是高级开发人员的人,我也经常看到以下代码:

try
{
  //do something
}
catch
{
  //Do nothing
}

或者有时他们将日志信息写入日志文件,如以下try catch

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

我只是想知道他们所做的是否是最佳做法?这让我感到困惑,因为在我看来,用户应该知道系统会发生什么。


阅读 94

收藏
2022-06-27

共1个答案

小编典典

我的异常处理策略是:

  • 要通过挂钩来捕获 所有未处理的异常Application.ThreadException event,然后决定:

    • 对于 UI 应用程序:通过道歉消息将其弹出给用户(WinForms)
    • 对于服务或控制台应用程序:将其记录到文件(服务或控制台)

然后我总是将 在外部运行的每一段代码 都包含在try/catch

  • WinForms 基础结构触发的所有事件(Load、Click、SelectedChanged…)
  • 第三方组件触发的所有事件

然后我附在“尝试/捕获”中

  • 我 __所知道的所有操作 可能不会一直有效 (IO 操作、具有潜在零除法的计算......)。在这种情况下,我会抛出一个新ApplicationException("custom message", innerException)的来跟踪真正发生的事情

此外,我尽我所能 正确地对异常进行排序 。有以下例外情况:

  • 需要立即显示给用户

  • 当它们发生时需要一些额外的处理来将它们放在一起以避免级联问题(即:在填充期间将 .EndUpdate 放在finally部分中TreeView

  • 用户不在乎,但重要的是要知道发生了什么。所以我总是记录它们:

  • 在事件日志中

  • 或在磁盘上的 .log 文件中

设计一些静态方法来处理 应用程序顶级错误处理程序中的异常是一种很好的做法。

我也强迫自己尝试:

  • 请记住 ,所有异常都会冒泡到顶层 。没有必要将异常处理程序放在任何地方。
  • 可重用或深度调用的函数不需要显示或记录异常:它们要么自动冒泡,要么在我的异常处理程序中使用一些自定义消息重新抛出。

所以最后:

坏的:

// DON'T DO THIS; ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

无用:

// DON'T DO THIS; IT'S USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

最后尝试没有捕获是完全有效的:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURRED OR NOT
    listView1.EndUpdate();
}

我在顶层做什么:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

我在一些被调用的函数中做了什么:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module:", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

异常处理(自定义异常)有很多关系,但我尝试记住的那些规则对于我所做的简单应用程序来说已经足够了。

这是一个扩展方法的示例,可以以一种舒适的方式处理捕获的异常。它们以可以链接在一起的方式实现,并且很容易添加自己的捕获异常处理。

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}
2022-06-27