最佳实践

cheatsheet

用控制语句控制流程 控制流程有异常
通过记录跟踪被忽略(吸收)的异常 忽略异常
使用 throw 重复异常 重新抛出异常 - throw new ArgumentNullException()throw ex
抛出预定义的系统异常 抛出与预定义系统异常类似的自定义异常
如果对应用程序逻辑至关重要,则抛出自定义/预定义异常 抛出自定义/预定义异常以在流中声明警告
捕获你要处理的异常 抓住每个例外

不要用例外管理业务逻辑

流程控制不应由异常完成。改为使用条件语句。如果可以使用 if-else 语句清楚地完成控件,请不要使用异常,因为它会降低可读性和性能。

请考虑 Bad Practices 先生的以下片段:

// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
    Console.WriteLine(myObject.ToString());
}

当执行到达 Console.WriteLine(myObject.ToString()); 时,应用程序将抛出 NullReferenceException。Bad Practices 先生意识到 myObject 为 null 并编辑了他的片段来捕捉和处理 NullReferenceException

// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
    try
    {
        Console.WriteLine(myObject.ToString());
    }
    catch(NullReferenceException ex)
    {
        // Hmmm, if I create a new instance of object and assign it to myObject:
        myObject = new object();
        // Nice, now I can continue to work with myObject
        DoSomethingElseWithMyObject();
    }
}

由于前一个片段只包含异常逻辑,如果 myObject 此时不为空,我该怎么办?我应该在哪里介绍这部分逻辑?在 Console.WriteLine(myObject.ToString()); 之后?在 try...catch 街区之后怎么样?

最佳实践先生怎么样?他怎么处理这个?

// This is a snippet example for DO
object myObject;
void DoingSomethingWithMyObject()
{
    if(myObject == null)
        myObject = new object();
    
    // When execution reaches this point, we are sure that myObject is not null
    DoSomethingElseWithMyObject();
}

Best Practices 先生用更少的代码和清晰易懂的逻辑实现了相同的逻辑。

不要重新抛出异常

重新抛出异常是昂贵的。它对性能产生负面影响。对于常规失败的代码,你可以使用设计模式来最小化性能问题。本主题描述了两种在异常可能会显着影响性能时非常有用的设计模式。

不要在没有记录的情况下吸收异常

try
{
    //Some code that might throw an exception
}
catch(Exception ex)
{
    //empty catch block, bad practice
}

永远不要吞下例外。忽略异常将节省那一刻,但会在以后为可维护性创建一个混乱。记录异常时,应始终记录异常实例,以便记录完整的堆栈跟踪,而不是仅记录异常消息。

try
{
    //Some code that might throw an exception
}
catch(NullException ex)
{
    LogManager.Log(ex.ToString());
}

不要捕捉你无法处理的异常

许多资源(例如资源) 强烈建议你考虑为什么要在捕获它的地方捕获异常。如果你可以在该位置处理异常,则应该只捕获异常。如果你可以在那里帮助缓解问题,例如尝试替代算法,连接到备份数据库,尝试其他文件名,等待 30 秒并再次尝试,或通知管理员,你可以捕获错误并执行此操作。如果没有什么可以合理合理地做,只需放手并让异常处理更高层次。如果异常是充满灾难性的,并且由于问题的严重性,除了整个程序崩溃之外没有合理的选择,那么让它崩溃。

try
{
    //Try to save the data to the main database.
}
catch(SqlException ex)
{
    //Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the exception bubble up to a level where it can be handled.