最佳實踐

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.