異常簡介編程
C sharp中的異經常使用於處理系統級和應用程序級的錯誤狀態,它是一種結構化、統一的類型安全的處理機制。異常處理相對於返回錯誤代碼的一個最大優勢在於,異常能夠被自動傳遞,這樣,在編程時異常更加難以被忽視。數組
C#的異常機制很是相似於C++的異常處理機制,可是仍是有一些重要的區別:安全
1,在C#中,全部的異常必須由從System.Exception派生的類來表示。在 C++ 中,可使用任何類型的任何值表示異常。app
2,在C#中,利用finally 塊可編寫在正常執行和異常狀況下都將執行的終止代碼。在C++中,很難在不重複代碼的狀況下編寫這樣的代碼。ide
3,C# 中,系統級的異常如溢出、被零除和 null 等都對應地定義了與其匹配的異常類,而且與應用程序級的錯誤狀態處於同等地位。函數
引起異常的緣由線程
1.throw 語句用於當即無條件地引起異常。控制永遠不會到達緊跟在 throw 後面的語句。調試
2.在執行C#語句和表達式的過程當中,有時會出現一些例外狀況,使某些操做沒法正常完成,此時就會引起一個異常。例如,在整數除法運算中,若分母爲零引起 System.DivideByZeroException。日誌
System.Exception 類orm
System.Exception類是全部異常的基類型。若干個異常類直接從Exception繼承。
ApplicationException和SystemException繼承該類,幾乎是全部運行時異常的基礎。
此類具備一些全部異常共享的值得注意的屬性:
· Message 是string類型的一個只讀屬性,它包含關於所發生異常的緣由的描述(易於人工閱讀)。
· InnerException 是 Exception 類型的一個只讀屬性。
若是它的值不是 null,則它所引用的是指致使了當前異常的那個異常,即表示當前異常是在處理那個InnerException的catch 塊中被引起的。
若是它的值爲 null,則表示該異常不是由另外一個異常引起的。
以這種方式連接在一塊兒的異常對象的數目能夠是任意的。此屬性可用來在異常處理過程當中建立和保留一系列異常。可以使用此屬性建立一個新異常來包含之前捕捉的異常。原始異常可
由 InnerException 屬性中的第二個異常捕獲,這使處理第二個異常的代碼能夠檢查附加信息。
例如,假設有一個讀取文件並格式化相應數據的方法。 代碼嘗試從文件讀取,但引起FileException。該方法捕捉 FileException 並引起 BadFormatException。在此狀況下,FileException 可保存在 BadFormatException 的 InnerException 屬性中。
爲提升調用方肯定異常引起緣由的能力,有時可能須要方法捕捉幫助器例程引起的異常,而後引起一個進一步指示已發生的錯誤的異常。 能夠建立一個更有意義的新異常,其中內部異常引用能夠設置爲原始異常。 而後能夠針對調用方引起這種更有意義的異常。 請注意,使用此功能,能夠建立以最早引起的異常做爲結束點的一系列相連接的異常。
·StackTrace 屬性
此屬性包含可用來肯定錯誤發生位置的堆棧跟蹤。若是有可用的調試信息,則堆棧跟蹤包含源文件名和程序行號。
·Data 屬性:此屬性是能夠保存任意數據(以鍵值對的形式)的IDictionary。
異常的處理方式
先執行try裏面的語句,若是try裏面的語句拋出了錯誤,就會被catch捕獲,因此就會中斷try裏面語句的執行轉而執行catch裏面的語句,若是try裏面的語句都執行完了也沒有拋出錯誤,那麼catch裏的語句就沒有機會執行了。最後不論try順利運行完畢,仍是try拋出了錯誤被catch語句捕獲並執行了catch的語句都要接着執行finally裏面的語句。
發生異常時,系統將搜索能夠處理該異常的最近的 catch 子句(根據該異常的運行時類型來肯定)。首先,搜索當前的方法以查找一個詞法上包含着它的 try 語句,並按順序考察與該 try 語句相關聯的各個 catch 子句。若是上述操做失敗,則在調用了當前方法的方法中,搜索在詞法上包含着當前方法調用代碼位置的 try 語句。此搜索將一直進行下去,直到找到能夠處理當前異常的 catch 子句(該子句指定一個異常類,它與當前引起該異常的運行時類型屬於同一個類或是該運行時類型所屬類的一個基類)。注意,沒有指定異常類的 catch 子句能夠處理任何異常。找到匹配的 catch 子句後,系統將把控制轉移到該 catch 子句的第一條語句。在 catch 子句的執行開始前,系統將首先按順序執行嵌套在捕捉到該異常的 try 語句裏面的全部 try 語句所對應的所有 finally 子句。
若是沒有找到匹配的 catch 子句,則發生下列兩種狀況之一:
· 若是對匹配的 catch 子句的搜索到達一個靜態構造函數或靜態字段初始值設定項,則在致使調用該靜態構造函數的代碼位置引起 System.TypeInitializationException。該 System.TypeInitializationException 的內部異常將包含最初引起的異常。
· 若是對匹配的 catch 子句的搜索到達最初啓動當前線程的代碼處,則該線程的執行就會終止。此類終止會產生什麼影響,應由實現來定義。
特別值得注意的是在析構函數執行過程當中發生的異常。若是在析構函數執行過程當中發生異常且該異常未被捕獲,則將終止該析構函數的執行,並調用它的基類的析構函數(若是有)。若是沒有基類(如 object 類型中的狀況),或者若是沒有基類析構函數,則該異常將被忽略。
異常類的層次結構
System.ArrayTypeMismatchException:當存儲一個數組時,若是因爲被存儲的元素的實際類型與數組的實際類型不兼容而致使存儲失敗,就會引起此異常。
System.DivideByZeroException:在試圖用零除整數值時引起。
System.IndexOutOfRangeException:在試圖使用小於零或超出數組界限的下標索引數組時引起。
System.InvalidCastException:當從基類型或接口到派生類型的顯式轉換在運行時失敗時引起。
System.NullReferenceException:在須要使用引用對象的場合,若是使用 null 引用時引起。
System.OutOfMemoryException:在分配內存(經過 new)的嘗試失敗時引起。
System.OverflowException:在 checked 上下文中的算術運算溢出時引起。
System.StackOverflowException:當執行堆棧因爲保存了太多掛起的方法調用而耗盡時,就會引起此異常;這一般代表存在很是深或無限的遞歸。
System.TypeInitializationException:在靜態構造函數引起異常而且沒有能夠捕捉到它的 catch 子句時引起。
產生TypeInitializationException的狀況就包含如下幾種:
例如訪問ClassHelper.StaticString,因爲靜態成員Field的初始化產生異常,所以調用ClassHelper.StaticString會拋出TypeInitializationException。
例如訪問ClassHelper.Field。
例如ClassHelper helper = new ClassHelper()。
異常處理準則
4. 能夠在非最上層拋出自定義異常。若是是自定義異常,請保證其是可序列化的,而且保證其實現了Exception的三個構造函數。自定義異常不要繼承Exception基類。相反,繼承ApplicationException
5.異常的拋出與截獲須要不少的CPU時間,不要在全部的方法中寫的try - catch。只在有可能有某個特定的異常發生的方法中使用它。
6.始終捕獲特定的異常,而不是通常的異常和系統異常。
7.當發生異常時,爲了確保清理佔據的資源,使用try / finally塊。在finally子句中關閉的資源。使用try / finally塊,即便發生異常,也能確保資源disposed。
8.在一個catch塊中的代碼都應該至少部分地處理了所捕捉的異常。不然,就不要使用catch塊。
9.從構造函數中拋出異常。由於構造函數沒有返回值,因此沒有簡單的方法來想構造函數的調用者發出構造失敗的信號,這時即可以經過拋出異常來作到。好比構造參數與指定條件不符時,就拋出一個異常。
10.在以上前提的保證下,能夠在非最上層使用AOP截獲(intercept)異常而進行日誌記錄,這樣經過日誌記錄,咱們能夠了解系統的運行狀態。也能夠有一個應用程序級(線程級)的錯誤處理程序,您能夠用它處理全部通常異常。在一個'意外通常錯誤'中,這個錯誤處理程序應該捕獲該異常並記錄他,除此以外,在應用程序關閉以前應該作出友好的信息提示或者容許用戶選擇忽略異常繼續。
記不起在哪裏看到過這樣一句話:在軟件實現中,異常和日誌都是重要的質量保證手段,異常和日誌老是同時出現的。能夠說,異常是日誌記錄的重要/主要組成部分。
調試
使用斷點進入調試模式。