詳解C#編程中異常的創(chuàng)建和引發(fā)以及異常處理
創(chuàng)建和引發(fā)異常
異常用于指示在運行程序時發(fā)生了錯誤。此時將創(chuàng)建一個描述錯誤的異常對象,然后使用 throw 關(guān)鍵字“引發(fā)”該對象。然后運行時搜索最兼容的異常處理程序。
當存在下列一種或多種情況時,程序員應引發(fā)異常:
方法無法完成其中定義的功能。
例如,如果方法的參數(shù)具有無效值:
static void CopyObject(SampleClass original) { if (original == null) { throw new System.ArgumentException("Parameter cannot be null", "original"); } }
根據(jù)對象的狀態(tài),對某個對象進行不適當?shù)恼{(diào)用。
一個示例可能嘗試對只讀文件執(zhí)行寫操作。在對象狀態(tài)不允許某項操作的情況下,引發(fā) InvalidOperationException 的一個實例或基于此類的派生類的對象。以下為引發(fā) InvalidOperationException 對象的方法的示例:
class ProgramLog { System.IO.FileStream logFile = null; void OpenLog(System.IO.FileInfo fileName, System.IO.FileMode mode) {} void WriteLog() { if (!this.logFile.CanWrite) { throw new System.InvalidOperationException("Logfile cannot be read-only"); } // Else write data to the log and return. } }
方法的參數(shù)導致了異常。
在此情況下,應捕獲原始異常并創(chuàng)建一個 ArgumentException 實例。原始異常應作為 InnerException 參數(shù)傳遞給 ArgumentException 的構(gòu)造函數(shù):
static int GetValueFromArray(int[] array, int index) { try { return array[index]; } catch (System.IndexOutOfRangeException ex) { System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex); throw argEx; } }
異常包含一個名為 StackTrace 的屬性。此字符串包含當前調(diào)用堆棧上的方法的名稱,以及為每個方法引發(fā)異常的位置(文件名和行號)。 StackTrace 對象由公共語言運行時 (CLR) 從 throw 語句點開始自動創(chuàng)建,因此必須從堆棧跟蹤的開始點引發(fā)異常。
所有異常都包含一個名為 Message 的屬性。應該設(shè)置此字符串來解釋發(fā)生異常的原因。注意,不應將安全敏感信息放在消息文本中。除 Message 之外,ArgumentException 還包含一個名為 ParamName 的屬性,應將該屬性設(shè)置為導致引發(fā)異常的參數(shù)的名稱。對于屬性設(shè)置器,ParamName 應設(shè)置為 value。
公共的受保護方法應在其無法完成預期功能時引發(fā)異常。引發(fā)的異常類應該是符合錯誤條件的最確切的可用異常。這些異常應編寫為類功能的一部分,派生類或?qū)υ碱惖母聭A粝嗤男袨?,以實現(xiàn)向后兼容性。
引發(fā)異常時要避免的情況
下表確定了在引發(fā)異常時要避免的做法:
- 不應使用異常來更改正常執(zhí)行過程中的程序流程。異常只能用于報告和處理錯誤條件。
- 只能引發(fā)異常,而不能作為返回值或參數(shù)返回異常。
- 不要從自己的源代碼中有意引發(fā) System.Exception、System.SystemException、System.NullReferenceException 或 System.IndexOutOfRangeException。
- 不要創(chuàng)建可在調(diào)試模式下引發(fā)但不會在發(fā)布模式下引發(fā)的異常。若要在開發(fā)階段確定運行時錯誤,請改用調(diào)試斷言。
定義異常類
程序可以引發(fā) System 命名空間中的預定義異常類(前面注明的情況除外),或通過從 Exception 派生來創(chuàng)建它們自己的異常類。派生類至少應定義四個構(gòu)造函數(shù):一個是默認構(gòu)造函數(shù),一個用來設(shè)置消息屬性,一個用來設(shè)置 Message 屬性和 InnerException 屬性。第四個構(gòu)造函數(shù)用于序列化異常。新異常類應該可序列化。例如:
public class InvalidDepartmentException : System.Exception { public InvalidDepartmentException() : base() { } public InvalidDepartmentException(string message) : base(message) { } public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { } // A constructor is needed for serialization when an // exception propagates from a remoting server to the client. protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } }
僅當新屬性提供的數(shù)據(jù)有助于解決異常時,才應將其添加到異常類。如果向派生的異常類添加了新屬性,則應重寫 ToString() 以返回添加的信息。
異常處理
C# 程序員可使用 try 塊對可能受異常影響的代碼進行分區(qū)。關(guān)聯(lián)的 catch 塊用于處理任何結(jié)果異常。一個包含代碼的 finally 塊,無論 try 塊中是否引發(fā)異常(例如,釋放在 try 塊中分配的資源),這些代碼都會運行。一個 try 塊需要一個或多個關(guān)聯(lián)的 catch 塊或一個 finally 塊,或兩者。
以下示例給出了一個 try-catch 語句,一個 try-finally 語句,和一個 try-catch-finally 語句。
try { // Code to try goes here. } catch (SomeSpecificException ex) { // Code to handle the exception goes here. // Only catch exceptions that you know how to handle. // Never catch base class System.Exception without // rethrowing it at the end of the catch block. } try { // Code to try goes here. } finally { // Code to execute after the try block goes here. } try { // Code to try goes here. } catch (SomeSpecificException ex) { // Code to handle the exception goes here. } finally { // Code to execute after the try (and possibly catch) blocks // goes here. }
不帶有 catch 或 finally 塊的 try 塊將導致編譯器錯誤。
Catch 塊
catch 塊可以指定要捕捉的異常的該類型。類型規(guī)范稱為“異常篩選器”。異常類型應從 Exception 派生出來。一般而言,不會將 Exception 指定為異常篩選器,除非您了解如何處理 try 塊中可能引發(fā)的所有異常,或者您在 catch 塊中包括了 throw 語句。
具有不同異常篩選器的多個 catch 塊可以串聯(lián)在一起。多個 catch 數(shù)據(jù)塊的計算順序是在代碼中從頂部到底部,但是,對于所引發(fā)的每個異常,都只執(zhí)行一個 catch 數(shù)據(jù)塊。與指定的準確類型或其基類最為匹配的第一個 catch 塊被執(zhí)行。如果 catch 塊沒有指定匹配異常篩選器,則 catch 塊就不具有選定的篩選器(如果語句有的話)。需要將帶有最具體的(即派生程度最高的)異常類的 catch 塊放在最前面。
當下列條件為真時,應該捕捉異常:
對引發(fā)異常的原因有具體的了解,并可實現(xiàn)特定的恢復,例如,在捕獲 FileNotFoundException 對象時提示用戶輸入新的文件名。
可以新建一個更具體的異常并引發(fā)該異常。
int GetInt(int[] array, int index) { try { return array[index]; } catch(System.IndexOutOfRangeException e) { throw new System.ArgumentOutOfRangeException( "Parameter index is out of range."); } }
希望在將異常傳遞出去進行額外處理前部分地處理異常。在下面的示例中,catch 塊用于在再次引發(fā)異常之前,向錯誤日志添加條目。
try { // Try to access a resource. } catch (System.UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
Finally 塊
可以使用 finally 塊清理在 try 塊中執(zhí)行的操作。如果存在,finally 塊將在最后執(zhí)行,在 try 塊和任何匹配 catch 的塊之后執(zhí)行。不管是否引發(fā)異?;蛘呤欠裾业脚c異常類型匹配的 catch 塊,finally 始終運行。
可以使用 finally 塊釋放資源(如文件流、數(shù)據(jù)庫連接和圖形句柄),而不用等待由運行時中的垃圾回收器來完成對象。
在下面的示例中,使用 finally 塊關(guān)閉在 try 塊中打開的文件。注意,在關(guān)閉文件之前要檢查該文件句柄的狀態(tài)。如果 try 塊無法打開文件,則文件句柄仍具有值 null,并且 finally 塊不會嘗試關(guān)閉它?;蛘撸绻?try 塊中成功打開該文件,則 finally 塊將關(guān)閉打開的文件。
System.IO.FileStream file = null; System.IO.FileInfo fileinfo = new System.IO.FileInfo("C:\\file.txt"); try { file = fileinfo.OpenWrite(); file.WriteByte(0xF); } finally { // Check for null because OpenWrite might have failed. if (file != null) { file.Close(); } }
欄 目:C#教程
下一篇:解析C#面向?qū)ο缶幊讨蟹椒ǎ╩ethod)的使用
本文標題:詳解C#編程中異常的創(chuàng)建和引發(fā)以及異常處理
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6729.html
您可能感興趣的文章
- 01-10C#通過反射獲取當前工程中所有窗體并打開的方法
- 01-10C#實現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實現(xiàn)由四周向中心縮小的窗體退出特效
- 01-10Extjs4如何處理后臺json數(shù)據(jù)中日期和時間
- 01-10C#編程實現(xiàn)自定義熱鍵的方法
- 01-10C#中DataGridView常用操作實例小結(jié)
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10asp.net中XML如何做增刪改查操作
- 01-10C#利用反射技術(shù)實現(xiàn)去掉按鈕選中時的邊框效果
- 01-10C#中查找Dictionary中的重復值的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻 器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當前操作系統(tǒng)已
隨機閱讀
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結(jié)
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 04-02jquery與jsp,用jquery
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什