C# 項目異常處理的總結

這兩天新的項目設計工作快完畢了,我要出一份新項目中的異常書寫規則.在msdn上查找了些資料,發現裏面很多都是程序員常犯的錯誤.總結出來,希望對大家有所提高.異常引發準則:不要返回錯誤代碼。

異常是報告框架中的錯誤的主要手段。通過引發異常來報告執行故障。

如果某一成員無法按預期方式成功執行,則應將這種情況視爲一個執行故障並引發一個異常。

如果代碼遇到繼續執行則不安全的情況,應考慮通過調用 System.Environment.FailFast(System.String)(.NET Framework 2.0 中的一種功能)來終止進程,而不是引發異常。儘可能不對正常控制流使用異常。

除了系統故障及可能導致爭用狀態的操作之外,框架設計人員還應設計一些 API 以便用戶可以編寫不引發異常的代碼。

例如,可以提供一種在調用成員之前檢查前提條件的方法,以便用戶可以編寫不引發異常的代碼。

考慮引發異常的性能影響。

記錄公共可調用的成員因成員協定衝突(而不是系統故障)而引發的所有異常,並將這些異常視爲協定的一部分。

包含在協定中的異常不應從一個版本更改到下一個版本。

不要包含可以根據某一選項引發或不引發異常的公共成員。

例如,不要定義如下所示的成員:Uri ParseUri(string uriValue, bool throwOnError)不要包含將異常作爲返回值或輸出參數返回的公共成員。

考慮使用異常生成器方法。

從不同的位置引發同一異常會經常發生。

爲了避免代碼膨脹,請使用幫助器方法創建異常並初始化其屬性。

不要從異常篩選器塊中引發異常。當異常篩選器引發異常時,公共語言運行庫 (CLR) 將捕獲該異常,然後該篩選器返回 false。此行爲與篩選器顯式執行和返回 false 的行爲無法區分,因此很難調試。避免從 finally 塊中顯式引發異常。

可以接受因調用引發異常的方法而隱式引發的異常。

異常處理準則:不要在框架代碼中捕捉非特定異常(如 System.Exception、System.SystemException 等)以至忽略錯誤。

下面的代碼示例演示的異常處理是不正確的。 public class BadExceptionHandlingExample1{ public void DoWork() { // Do some work that might throw exceptions. } public void MethodWithBadHandler() { try { DoWork(); } catch (Exception e) { // Swallow the exception and continue // executing. } }}複製代碼避免在應用程序代碼中捕捉非特定異常(如 System.Exception、System.SystemException 等)以至忽略錯誤。某些情況下,可以在應用程序中忽略錯誤,但這種情況極少。如果捕捉異常是爲了傳輸異常,則不要排除任何特殊異常。下面的代碼示例演示對以再次引發爲目的特殊異常進行的不正確測試。 public class BadExceptionHandlingExample2{ public void DoWork() { // Do some work that might throw exceptions. } public void MethodWithBadHandler() { try { DoWork(); } catch (Exception e) { if (e is StackOverflowException || e is OutOfMemoryException) throw; // Handle exception and continue // executing. } }}複製代碼如果瞭解特定異常在給定上下文中引發的條件,請考慮捕捉這些異常。不要過多使用 catch。通常應允許異常在調用堆棧中往上傳播。使用 try-finally 並避免將 try-catch 用於清理代碼。在書寫規範的異常代碼中,try-finally 比 try-catch 使用得更多。捕捉並再次引發異常時,首選使用空引發。這是保留異常調用堆棧的最佳方式。下面的代碼示例演示一個可引發異常的方法。 public void DoWork(Object anObject){ // Do some work that might throw exceptions. if (anObject == null) { throw new ArgumentNullException("anObject", "Specify a non-null argument."); } // Do work with o.}複製代碼下面的代碼示例演示捕捉一個異常,並在再次引發該異常時對它進行錯誤的指定。這會使堆棧跟蹤指向再次引發作爲錯誤位置,而不是指向 DoWork 方法。 public void MethodWithBadCatch(Object anObject){ try { DoWork(anObject); } catch (ArgumentNullException e) { System.Diagnostics.Debug.Write(e.Message); // This is wrong. throw e; // Should be this: // throw; }}複製代碼不要使用無參數 catch 塊來處理不符合 CLS 的異常(不是從 System.Exception 派生的異常)。支持不是從 Exception 派生的異常的語言可以處理這些不符合 CLS 的異常。捕捉和引發標準異常類型:Exception 和 SystemException不要引發 System.Exception 或 System.SystemException。不要在框架代碼中捕捉 System.Exception 或 System.SystemException,除非打算再次引發。避免捕捉 System.Exception 或 System.SystemException,在頂級異常處理程序中除外。ApplicationException不要引發 System.ApplicationException 或從該異常進行派生。InvalidOperationException如果處於不適當的狀態,則引發 System.InvalidOperationException 異常。如果沒有向屬性集或方法調用提供適當的對象當前狀態,則應引發 System.InvalidOperationException。例如,向已打開用於讀取的 System.IO.FileStream 寫入時,應引發 System.InvalidOperationException 異常。ArgumentException、ArgumentNullException 和 ArgumentOutOfRangeException如果向成員傳遞了錯誤的參數,則引發 System.ArgumentException 或其子類型之一。如果適用,首選派生程度最高的異常類型。在引發 System.ArgumentException 或其派生類型之一時,設置 System.ArgumentException.ParamName 屬性。此屬性存儲導致引發異常的參數的名稱。注意,使用其中一個構造函數重載可以設置該屬性。使用屬性 setter 的隱式值參數的名稱的值。不要允許公開可調用的 API 顯式或隱式引發 System.NullReferenceException、System.AccessViolationException、System.InvalidCastException 或 System.IndexOutOfRangeException。進行參數檢查以避免引發這些異常。引發這些異常會公開方法的實現細節,這些細節可能會隨時間發生更改。StackOverflowException不要顯式引發 System.StackOverflowException。此異常只應由公共語言運行庫 (CLR) 顯式引發。不要捕捉 System.StackOverflowException。以編程方式處理堆棧溢出極爲困難。應允許此異常終止進程並使用調試確定問題的根源。OutOfMemoryException不要顯式引發 System.OutOfMemoryException。此異常只應由 CLR 基礎結構引發。ComException 和 SEHException不要顯式引發 System.Runtime.InteropServices.COMException 或 System.Runtime.InteropServices.SEHException。這些異常只應由 CLR 基礎結構引發。不要顯式捕捉 System.Runtime.InteropServices.SEHException。ExecutionEngineException不要顯式引發 System.ExecutionEngineException。設計自定義異常:避免使用深的異常層次結構。一定要從 System.Exception 或其他常見基本異常之一派生異常。請注意,捕捉和引發標準異常類型中有一條規定,不應從 ApplicationException 派生自定義異常。異常類名稱一定要以後綴 Exception 結尾。應使異常可序列化。異常必須可序列化才能跨越應用程序域和遠程處理邊界正確工作。一定要在所有異常上都提供(至少是這樣)下列常見構造函數。請確保參數的名稱和類型與使用者相同.代碼如下: public class NewException : BaseException, ISerializable{ public NewException() { // Add implementation. } public NewException(string message) { // Add implementation. } public NewException(string message, Exception inner) { // Add implementation. } // This constructor is needed for serialization. protected NewException(SerializationInfo info, StreamingContext context) { // Add implementation. }}複製代碼一定要只在要求適合的權限後,才通過 System.Object.ToString 的重寫報告安全敏感信息。如果權限要求失敗,則返回一個不包括安全敏感信息的字符串。一定要以私有異常狀態存儲有用的安全敏感信息。請確保只有受信任的代碼才能獲取該信息。考慮提供異常屬性,以便可以以編程方式訪問除消息字符串之外與異常相關的額外信息。異常和性能:不要由於擔心異常可能會對性能造成不良影響而使用錯誤代碼。對於可能在常見方案中引發異常的成員,可以考慮使用 Tester-Doer 模式來避免與異常相關的性能問題。Doer的代碼如下: public class Doer{ // Method that can potential throw exceptions often. public static void ProcessMessage(string message) { if (message == null) { throw new ArgumentNullException("message"); } } // Other methods...}複製代碼Tester代碼如下: public class Tester{ public static void TesterDoer(ICollection messages) { foreach (string message in messages) { // Test to ensure that the call // won't cause the exception. if (message != null) { Doer.ProcessMessage(message); } } }}複製代碼對於可能在常見方案中引發異常的成員,可以考慮使用 TryParse 模式來避免與異常相關的性能問題。代碼如下: int i = 0; int j = 0; bool IsPre1 = Int32.TryParse("30",out i); bool IsPre2 = Int32.TryParse("12s",out j); //執行之後i = 30 , j = 0 ; IsPre1 = true, IsPre2 = false;複製代碼

發佈了9 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章