应该始终以以下方式重新引发异常:
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。 }