錯誤的出現並不總是程序員的原因,有時應用程序會因為用戶引發或運行代碼的環境而發生錯誤,無論如何我們都應相應的預測應用程序和代碼中出現的錯誤。C sharp中的異常用於處理系統級和應用程序級的錯誤狀態,它是一種結構化.統一的類型安全的處理機制。
在C#中所有的異常類型都繼承自System.Exception,也就是說,System.Exception是所有異常類的基類. 總起來說,其派生類分為兩種:
1).SystemException類: 所有的CLR提供的異常類型都是由SystemException派生。
2). ApplicationException類: 由用戶程序引發,用於派生自定義的異常類型,一般不直接進行實例化。
c#的異常 機制非常類似於c++的異常處理機制,但是還是有一些重要的區別:
1).在 C# 中,所有的異常必須由從 System.Exception 派生的類類型的實例來表示。在 C++ 中,可以使用任何類型的任何值表示異常。
2).在 C# 中,利用 finally 塊可編寫在正常執行和異常情況下都將執行的終止代碼。在 C++ 中,很難在不重復代碼的情況下編寫這樣的代碼。
3).C# 中,系統級的異常如溢出.被零除和 null 等都對應地定義了與其匹配的異常類,並且與應用程序級的錯誤狀態處於同等地位。
1.1 導致異常的原因
可以以兩種不同的方式引發異常。
1).使用 throw主動拋出異常,用於立即無條件地引發異常。控制永遠不會到達緊跟在 throw 后面的語句。
2).在執行 C# 語句和表達式的過程中,有時會出現一些例外情況,使某些操作無法正常完成,此時就會引發一個異常。例如,在整數除法運算中,如果分母為零,則會引發 System.DivideByZeroException。有關可能以此方式引發的各種異常的列表。
1.2 System.Exception 類
System.Exception 類是所有異常的基類型。此類具有一些所有異常共享的值得注意的屬性:
1).Message 是 string 類型的一個只讀屬性,它包含關於所發生異常的原因的描述(易於人工閱讀)
2).Source 導致異常的應用程序名或對象名
3).Data 這個屬性可以給異常添加鍵/值語句,以提供關於異常的額外信息
4).StackTrace 棧上方法調用的詳細信息,它有助於跟蹤拋出異常的方法
5).InnerException 是 Exception 類型的一個只讀屬性。如果它的值不是 null,則它所引用的是導致了當前異常的那個異常,即表示當前異常是在處理那個 InnerException 的 catch 塊中被引發的。否則,它的值為 null,則表示該異常不是由另一個異常引發的。
1.3 異常的處理方式
1).程序在try塊中發生異常或遇到一條throw語句,會立刻查找與這個try對應的catch塊(根據該異常的運行時類型來確定),如果有多個與try對應的catch塊,則會查找與catch塊對應的異常類(注意,沒有指定異常類的 catch 子句和catch(Exception)一樣可以處理任何異常)。
2).程序在try塊中發生異常或遇到一條throw語句,系統會立即退出棧上所有的方法調用,異常處后面的代碼都不會執行,此時,中間方法調用中的所有局部變量都會超出作用域。
3).無論是否拋出異常,finally塊都會執行,可以用於清理資源或執行通常要在try或catch塊末尾執行的其他操作(如刪除對象或關閉已打開的對象)。
4).try對應多個catch塊時,程序只執行它在可用的catch塊列表中第一個合適的catch塊,所以,最先編寫catch塊用於處理非常特殊的錯誤,接着比較一般的塊,順序很重要。
5).嵌套try...catch,外層拋出的異常外層catch捕獲處理,內層拋出的異常內層catch捕獲處理,如果內層對應沒有catch,則外層Catch處理,如外層也沒Catch,則.NET運行庫處理。
6).在Catch中拋出或發生異常,拋出或發生異常后面的代碼不會運行,執行finally塊中的代碼后跳出當前等級的異常處理,由上層Catch捕獲,如果沒有,則由.NET運行庫捕獲。
7).有時拋出一個異常后,代碼中沒有catch塊能夠處理這類異常。實際上.NET運行庫把整個程序放在另一個更大try塊中,對每個.NET程序它都會這么做。它可以捕獲任何類型的異常,程序流會退出程序,由.NET運行庫中的catch塊捕獲它。
1.4用戶自定義異常
創建自定義異常類應嚴格遵循幾個原則
1). 聲明可序列化(用於進行系列化,當然如果你不需要序列化。那么可以不聲明為可序列化的)
2). 添加一個默認的構造函數
3). 添加包含message的構造函數
4). 添加一個包含message,及內部異常類型參數的構造函數
5). 添加一個序列化信息相關參數的構造函數.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyException : ApplicationException { private string message; public MyException() : base() { } public MyException(string str) :base(str) { } public MyException(string str, Exception inner) : base(str, inner) { } } class Program { static void Main(string[] args) { try { while (true) { try { Console.WriteLine("Input a Number between 0-5"); string userInput; userInput = Console.ReadLine(); if ("" == userInput) { throw new MyException("throw my exception"); break; } int nNum = Convert.ToInt32(userInput); if (nNum < 0 || nNum > 5) { throw new IndexOutOfRangeException("you type in " + userInput); } Console.WriteLine("You Number was " + nNum); } catch (MyException me) { Console.WriteLine("catch a myself exception"); } catch (IndexOutOfRangeException ex) { Console.WriteLine("You should Input a Number between 0-5"); throw new MyException("throw in catch"); } catch (Exception e) { Console.WriteLine("Error Message is " + e.Message); } finally { Console.WriteLine("Thank You"); } } } catch(MyException m) { Console.WriteLine("Hi, l catch a Exception"); Console.WriteLine(m.Message); } Console.ReadLine(); } } }
1.5公共異常類
下列異常由某些 C# 操作引發。
System.ArrayTypeMismatchException
當存儲一個數組時,如果由於被存儲的元素的實際類型與數組的實際類型不兼容而導致存儲失敗,就會引發此異常。
System.DivideByZeroException
在試圖用零除整數值時引發。
System.IndexOutOfRangeException
在試圖使用小於零或超出數組界限的下標索引數組時引發。
System.InvalidCastException
當從基類型或接口到派生類型的顯式轉換在運行時失敗時,就會引發此異常。
System.NullReferenceException
在需要使用引用對象的場合,如果使用 null 引用,就會引發此異常。
System.OutOfMemoryException
在分配內存(通過 new)的嘗試失敗時引發。
System.OverflowException
在 checked 上下文中的算術運算溢出時引發。
System.StackOverflowException
當執行堆棧由於保存了太多掛起的方法調用而耗盡時,就會引發此異常;這通常表明存在非常深或無限的遞歸。
System.TypeInitializationException
在靜態構造函數引發異常並且沒有可以捕捉到它的 catch 子句時引發。