異常反模式
吞嚥異常
應該總是以下列方式重新丟擲異常:
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.
}