12. 不要捕获所有异常
翻译概述:
在传统的C++中,对于大多数错误逻辑使用返回错误码的方式来定义。从而使程序逻辑中充斥了大量的条件判断逻辑,严重的影响了代码的可维护性和美观。而异常机制为开发提供了一套相对独立和易管理的错误处理方式,因此,在目前的大多数程序设计语言中都提供了对异常的支持,包括C++。
但是,异常属于一个脱离程序逻辑之外的控制流程,因此,对异常的滥用很多时候反而会降低程序逻辑的可维护性和易读性。(相信大多数老程序员都有过在修Bug时毫无原则的添加异常捕获逻辑的经历)而FxCop中的这条规则就实现了对异常捕获滥用的检查。
原文引用:
Do not catch general exception types
Rule Description General exceptions should not be caught. How to Fix Violations To fix a violation of this rule, catch a more specific exception, or re-throw the general exception as the last statement in the catch block. When to Exclude Messages Do not exclude a message from this rule. Catching general exception types can hide run-time problems from the library user, and can complicate debugging. Example Code The following example shows a type that violates this rule and a type that correctly implements the catch block. [C#] using System; using System.IO; namespace DesignLibrary { // Creates two violations of the rule. public class GenericExceptionsCaught { FileStream inStream; FileStream outStream; public GenericExceptionsCaught(string inFile, string outFile) { try { inStream = File.Open(inFile, FileMode.Open); } catch(SystemException e) { Console.WriteLine("Unable to open {0}.", inFile); } try { outStream = File.Open(outFile, FileMode.Open); } catch { Console.WriteLine("Unable to open {0}.", outFile); } } } public class GenericExceptionsCaughtFixed { FileStream inStream; FileStream outStream; public GenericExceptionsCaughtFixed(string inFile, string outFile) { try { inStream = File.Open(inFile, FileMode.Open); } // Fix the first violation by catching a specific exception. catch(FileNotFoundException e) { Console.WriteLine("Unable to open {0}.", inFile); } try { outStream = File.Open(outFile, FileMode.Open); } // Fix the second violation by re-throwing the generic // exception at the end of the catch block. catch { Console.WriteLine("Unable to open {0}.", outFile); throw; } } } } [Visual Basic] Imports System Imports System.IO Namespace DesignLibrary ' Creates two violations of the rule. Public Class GenericExceptionsCaught Dim inStream As FileStream Dim outStream As FileStream Sub New(inFile As String, outFile As String) Try inStream = File.Open(inFile, FileMode.Open) Catch ex As SystemException Console.WriteLine("Unable to open {0}.", inFile) End Try Try outStream = File.Open(outFile, FileMode.Open) Catch Console.WriteLine("Unable to open {0}.", outFile) End Try End Sub End Class Public Class GenericExceptionsCaughtFixed Dim inStream As FileStream Dim outStream As FileStream Sub New(inFile As String, outFile As String) Try inStream = File.Open(inFile, FileMode.Open) ' Fix the first violation by catching a specific exception. Catch ex As FileNotFoundException Console.WriteLine("Unable to open {0}.", inFile) End Try Try outStream = File.Open(outFile, FileMode.Open) ' Fix the second violation by re-throwing the generic ' exception at the end of the catch block. Catch Console.WriteLine("Unable to open {0}.", inFile) Throw End Try End Sub End Class End Namespace [C++] #using <mscorlib.dll> using namespace System; using namespace System::IO; namespace DesignLibrary { // Creates two violations of the rule. public __gc class GenericExceptionsCaught { FileStream* inStream; FileStream* outStream; public: GenericExceptionsCaught(String* inFile, String* outFile) { try { inStream = File::Open(inFile, FileMode::Open); } catch(SystemException* e) { Console::WriteLine(S"Unable to open {0}.", inFile); } try { outStream = File::Open(outFile, FileMode::Open); } catch(Exception* e) { Console::WriteLine(S"Unable to open {0}.", outFile); } } }; public __gc class GenericExceptionsCaughtFixed { FileStream* inStream; FileStream* outStream; public: GenericExceptionsCaughtFixed(String* inFile, String* outFile) { try { inStream = File::Open(inFile, FileMode::Open); } // Fix the first violation by catching a specific exception. catch(FileNotFoundException* e) { Console::WriteLine(S"Unable to open {0}.", inFile); } try { outStream = File::Open(outFile, FileMode::Open); } // Fix the second violation by re-throwing the generic // exception at the end of the catch block. catch(Exception* e) { Console::WriteLine(S"Unable to open {0}.", outFile); throw; } } }; } Related Rules Rethrow to preserve stack details See Also |
引起的原因:
使用catch语句捕获System.Exception或System.SystemException类型的异常,或者使用了无类型catch子句。
描述:
不应该捕获所有的异常。
修复:
只捕获部分指定类型的异常,或者在catch语句块的结尾将一半类型的异常重新抛出。
例外:
不要禁用这条规则。捕获所有的异常将会隐藏运行时的一些问题,这样将会使用户调试程序变得复杂。
例程:
原文的例子中,分别用三种语言分别演示错误的用法和如何修复这个错误。
其中,类型GenericExceptionsCaught在构造函数中有两段捕获异常的代码,第一段捕获了System.SystemException类型的异常,第二段捕获了所有的异常。
而类型GenericExceptionsCaughtFixed中,演示了如何修正这两段不正确的逻辑,对于第一段逻辑,使用了一个特定类型的异常捕获语句代替捕获SystemException。第二段逻辑将异常重新抛出。