1. 程式人生 > >《.NET 設計規範》第 7 章:異常

《.NET 設計規範》第 7 章:異常

運行 finall 輸出參數 特定 所有 具體類 撰寫文檔 撰寫 gin

第 7 章:異常

  異常與各種面向對象語言集成得非常好。

  異常增強了 API 的一致性。

  在用返回值來報告錯誤時,錯誤處理的代碼與可能會發生錯誤的代碼距離總是很近。

  更容易使錯誤處理的帶碼全局化。

  錯誤碼很容易被忽略,而且經常會被忽略。

  異常可以包含豐富的信息來對錯誤的原因加以描述。

  異常允許用戶定義未處理異常的處理程序。

  異常可以包含豐富的信息來對錯誤額原因加以描述。

  異常允許用戶定義未處理異常的處理程序。

  異常有助於檢測。

7.1 拋出異常

  不要返回錯誤碼。

  要通過拋出異常的放回來報告操作失敗。

  考慮在代碼遇到嚴重問題且無法繼續安全地執行時,通過調用 System.Environment.FailFast 來終止進程,而不要拋出異常。

  不要在正常的控制流中使用異常,如果能夠避免的話。

  考慮拋出異常可能會對性能造成的影響。對大多數的應用程序來說,每秒拋出 100 個異常很可能會嚴重地影響性能。  

  要為所有的異常撰寫文檔,並把它們作為契約的一部分 - 如果異常是因為在調用公有成員時違反了它的契約而拋出的(非系統失敗)。

  不要讓公有成員根據某個選項來決定是否拋出異常。

  不要把異常用作公有成員的返回值或輸出參數。

  考慮使用輔助方法來創建異常。

  不要在異常過濾程序中拋出異常。

  避免顯式地從 finally 代碼塊中拋出異常。隱式地拋出異常,即在調用其它方法時由其它方法拋出異常,是可以接受的。

 

7.2 為拋出的異常選擇合適的類型

  不要為了通報使用錯誤而創建新的異常類型。在這種情況下應該拋出框架中已有的異常。

  考慮為程序錯誤創建並拋出自定義的異常 - 如果對它的處理方式和對其它異常的處理方式有所不同。否則,應該拋出已有的異常。

  不要創建新的異常類型 - 如果對該錯誤的處理和對框架中已有異常的並沒有什麽不同。在這種情況下應該拋出框架中已有的異常。

  要創建新的異常類型來傳達獨一無二的程序錯誤 - 如果不能通過框架中已有的異常來傳達該錯誤。

  避免設計出會導致系統失敗的 API。如果此類失敗可能會發生,那麽在發生系統失敗時應該調用 Environment.FailFast,而不應該拋出異常。

  不要僅僅為了擁有自己的異常而創建並使用新的異常。

  要使用合理的、最具針對性(最底層派生類)的異常。

  要在拋出異常時為開發人員提供豐富而有意義的錯誤消息。

  要確保異常消息的語法正確無誤。

  要確保異常消息中的每個句子都有句號。

  避免在異常消息這種使用問號和驚嘆號。

  不要在沒有得到許可的情況下在異常消息中泄漏安全消息。

  考慮把組件拋出的異常消息本地化 - 如果想讓沐浴為其它語言的開發人員也能使用組件。

  不要在框架的代碼捕獲具體類型不確定的異常(比如 System.Exception、System.SystemException,等等)時,把錯誤吞了。

  避免在應用程序的代碼中,在捕獲具體類型不確定的異常(比如 System.Exception、System.SystemException,等等)時,把錯誤吞了。

  不要把任何特殊的異常排除在外 - 如果編寫 catch 代碼塊的目的就是為了轉移異常。

  考慮捕獲特定類型的異常 - 如果確實理解該異常在具體環境中產生的原因,並能對錯誤做出適當的反應。

  不要捕獲不應該捕獲的異常。通常應該允許異常沿著調用棧向上遊傳遞。

  要在進行清理工作時使用 try-finally,避免使用 try-catch。對精心編寫的異常代碼來說,try-finally 的使用頻率要比 try-catch 高得多。

  要在捕獲並重新拋出異常時使用空的 throw 語句。這是保持異常調用棧不變的最好方法。

  不要用無參數的 catch 塊來處理不符合 CLS 規範的異常(不是派生自 System.Exception 的異常)。

  考慮對較低層次拋出的異常進行適當地封裝 - 如果較低層次的異常在較高層次的運行環境中沒有什麽意義。

  避免捕獲並封裝具體類型不確定的異常。

  要在對異常進行封裝時為其指定內部異常。

7.3 標準異常類型的使用

  不要拋出 System.Exception 或 System.SystemExceptio 異常。

  不要在框架代碼中捕獲 System.Exception 或 System.SystemException 異常,除非打算重新拋出。

  避免捕獲 System.Exception 或 Systen.SystemException 異常,除非是在頂層的異常處理器中。

  不要拋出 System.ApplicationException 或從它派生新類。

  要拋出 InvalidaOperationException 異常 - 如果對象處於不正確的狀態。

  要在用戶傳入無效參數時拋出 ArgumentException 異常或其子類型。如果可以的話,要盡量使用位於繼承層次末尾的異常類型。

  要在拋出 ArgumentException 異常或其子類時設置 ParamName 屬性。

  要在屬性的 setter 中,以 value 作為 value 隱式參數的名字。

  不要讓公共 API 顯式地或隱式地拋出 NullReferenceException、AccessViolationException 或 IndexOutOfRangeException 異常。這些異常時專門留給執行引擎來拋出的,大多數情況下它們表示代碼存在缺陷。

  不要顯式地拋出 StackOverflowException 異常。應該只有 CLR 才能顯式地拋出該異常。

  不要捕獲 StackOverflowException 異常。

  不要顯式地拋出 OutOfMemoryException 異常。應該只有 CLR 才能拋出異常。

  不要顯示地拋出 ComException、ExecutingEngineException 及 SEHException 異常,應該只有 CLR 才能拋出這些異常。

7.4 自定義異常的設計

  要從 System.Exception 或其它常用的異常基類派生新的異常。

  避免太深的繼承層次。

  要在命名異常類時使用“Exception”後綴。

  要使異常可序列化。為了使異常能夠在跨應用程序域和跨遠程邊界時仍能正常使用,這樣做是必須的。

  要為所有的異常(至少)提供下面這些常用的構造函數。

  要通過 ToString 的一個覆蓋方法來報告與安全性有關的消息,前提是必須先獲得相應的許可。

  要把與安全性有關的信息保存在私有的異常狀態中,並確保只有可信賴的代碼才能得到該信息。

  考慮為異常定義屬性,這樣就能從程序中取得除了消息字符串之外與異常有關的額外信息。

  

7.5 異常與性能

  不要因異常可能對性能造成負面影響而使用錯誤碼。

  考慮在成員中使用 Tester-Doer 模式來避免因異常而引起的性能問題 - 如果成員在常用場景中都可能拋出異常。

  考慮在成員中使用 Try-Parse 模式來避免因異常而引起的性能問題,如果成員在常用代碼中都可能會拋出異常。

  要在實現 Try-Parse 模式時使用“Try”前綴,並用布爾類型作為方法的返回類型。

  要為每個使用 Try-Parse 模式的方法提供一個會拋出異常的對應成員。

  

《.NET 設計規範》第 7 章:異常