异常反模式

吞咽异常

应该总是以下列方式重新抛出异常:

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.
}