C#异常反模式
示例
吞咽异常
应该始终以以下方式重新引发异常:
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)
{
//我们找到了
throw new AccountFoundException(account);
}
}
}
catch (AccountFoundException found)
{
Console.Write("这是您的帐户详细信息: " + found.Account.Details.ToString());
}这是一种更好的方法:
Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//我们找到了
found = account;
}
}
Console.Write("这是您的帐户详细信息: " + found.Details.ToString());捕获(异常)
在代码中几乎没有(有人说不!)捕获通用异常类型的原因。您应该只捕获预期会发生的异常类型,因为否则会在代码中隐藏错误。
try
{
var f = File.Open(myfile);
//做点什么
}
catch (Exception x)
{
//假设找不到文件
Console.Write("Could not open file");
//但可能由于文件处理代码中的错误而导致错误是NullReferenceException?
}最好做:
try
{
var f = File.Open(myfile);
//做点什么 which should normally not throw exceptions
}
catch (IOException)
{
Console.Write("File not found");
}
//不幸的是,这个不是从上面得出的,所以单独声明
catch (UnauthorizedAccessException)
{
Console.Write("Insufficient rights");
}如果发生任何其他异常,我们有意让应用程序崩溃,因此它直接进入调试器,我们可以解决问题。我们绝对不能在程序之外发生任何其他异常的情况下交付程序,因此发生崩溃不是问题。
以下示例也是一个不好的例子,因为它使用异常来解决编程错误。那不是他们设计的目的。
public void DoSomething(String s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
//实施在这里
}
try
{
DoSomething(myString);
}
catch(ArgumentNullException x)
{
//如果发生这种情况,我们会出现编程错误,我们应该检查
//为什么myString首先是null。
}