異常反模式

吞嚥異常

應該總是以下列方式重新丟擲異常:

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw;
}

重新丟擲如下所示的異常會混淆原始異常並丟失原始堆疊跟蹤。一個人永遠不應該這樣做! 捕獲和重新丟擲之前的堆疊跟蹤將丟失。

try
{
    ...
}
catch (Exception ex)
{
    ...
    throw ex;
}

棒球異常處理

不應該使用異常來代替正常的流控制結構, 如 if-then 語句和 while 迴圈。這種反模式有時被稱為棒球異常處理

以下是反模式的示例:

try
{
    while (AccountManager.HasMoreAccounts())
    {
        account = AccountManager.GetNextAccount();
        if (account.Name == userName)
        {
            //We found it
            throw new AccountFoundException(account);
        }
    }
}
catch (AccountFoundException found)
{
    Console.Write("Here are your account details: " + found.Account.Details.ToString());
}

這是一個更好的方法:

Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
    account = AccountManager.GetNextAccount();
    if (account.Name == userName)
    {
        //We found it
        found = account;
    }
}
Console.Write("Here are your account details: " + found.Details.ToString());

catch(例外)

幾乎沒有(有些人說沒有!)理由來捕獲程式碼中的泛型異常型別。你應該只捕獲你期望發生的異常型別,否則你將隱藏程式碼中的錯誤。

try 
{
     var f = File.Open(myfile);
     // do something
}
catch (Exception x)
{
     // Assume file not found
     Console.Write("Could not open file");
     // but maybe the error was a NullReferenceException because of a bug in the file handling code?
}

更好:

try 
{
     var f = File.Open(myfile);
     // do something which should normally not throw exceptions
}
catch (IOException)
{
     Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException) 
{
     Console.Write("Insufficient rights");
}

如果發生任何其他異常,我們有意讓應用程式崩潰,因此它直接進入偵錯程式,我們可以解決問題。除了這些之外的任何其他例外,我們不得釋出程式,因此崩潰不是問題。

以下是一個不好的例子,因為它使用異常來解決程式設計錯誤。這不是他們的設計目標。

public void DoSomething(String s)
{
     if (s == null)
         throw new ArgumentNullException(nameof(s));
     // Implementation goes here
}

try 
{    
     DoSomething(myString);
}
catch(ArgumentNullException x)
{
    // if this happens, we have a programming error and we should check
    // why myString was null in the first place.
}