异常反模式
吞咽异常
应该总是以下列方式重新抛出异常:
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.
}