c#銳利體驗
南京郵電學院李建忠(lijianzhong@263.***.**)
第十七講異常處理
異常處理
???????結構化異常處理是現代分布式環境下元件設計的乙個必要的環節,.***通用語言執行時從底層構造給予異常處理以堅實的支援。在c#中,異常物件被設計為封裝了各種異常資訊的類(system.exception及其繼承子類,和介面類似,它被推薦命名為加字尾「exception」的方式,但這並非必須),「try-catch-finally」語句和異常物件一起為c#元件設計提供從異常偵測,異常捕捉和處理等一攬子服務。先來看乙個典型的例子:
using system;
class test
????????catch (dividebyzeroexception e)
????????
????????catch (exception e)
????????
????}???
}示例將產生下面的輸出:
dividebyzeroexception --> system.dividebyzeroexception: attempted to divide by zero.
???at test.main()
我們在上面的try語句裡特意進行除零操作從而產生「除零異常」,在第乙個catch語句裡我們便捕捉到了「除零異常」——dividebyzeroexception,這是catch內指定的型別使然。從結果也可以看出,我們的第二個catch語句並沒有捕捉到任何其他異常。這個示例雖然簡短,卻為我們揭示了異常處理的基本模型。
???????首先我們將可能出現異常的語句放在try語句塊內,這樣的**中出現的異常才可能被偵測到並傳遞給catch語句。catch語句可以帶引數,也可以不帶引數。catch語句帶的引數型別只能為system.exception及其繼承子類。帶引數的catch語句將只捕捉引數指定型別的異常,對於其他的異常不予處理。不帶引數的catch語句相當於引數為system.exception型別的異常(即所有的異常),只不過不能獲取異常變數(如上面示例中的e)。乙個try語句塊後面可以匹配多個catch語句,以捕捉不同的異常型別。這裡必須注意的是多個catch語句的順序,後面的catch語句中的引數型別不能是前面型別的子類,也不能和前面的引數型別相同,無引數相當於system.exception型別。這個規定在針對特定型別的異常處理的意義下是很自然的——如果aexception型別是bexception型別的基類,那麼如果出現bexception型別的異常,catch(aexception e)也能夠捕捉得到,這樣下面將捕捉不到bexception型別的異常,catch(bexception e)也將失去意義。c#編譯器將對這種情況報錯。
???????那麼如果我們的catch語句的引數型別並沒有匹配try語句偵測到的異常型別會怎麼樣呢?當這種情況發生時,異常將在該語句的方法體內被丟擲。如果呼叫該方法的方法沒有相應的偵測和捕捉機制,那麼異常繼續被丟擲,直到**捉,或者被丟擲到應用程式的入口點main函式從而引起程式異常中斷執行。這種異常丟擲的機制對於在try語句之外出現的異常也同樣適用——偵測到但沒有捕捉到和沒有偵測的效果一樣!
???????另外一點需要注意的是程式一旦發生異常,那麼其後面的**將不被執行!上面示例中的console.writeline(「try end!」)就由於前面的**發生「除零異常」而沒有執行。這一點也決定了我們的**只能被偵測到一次異常,最多也只能捕捉一次異常!
但如果我們程式邏輯需要我們不管出現異常與否,都要執行某些任務緊急的**(典型的如關閉開啟的檔案,網路埠等)怎麼辦呢?c#提供finally語句來解決這種情況。finally語句不能單獨使用,它和try,catch有兩種搭配情況。try,catch,finally三者搭配構成try-catch-finally語句。看下面的例子:
using system;
public class test
????????catch(nullreferenceexception e)
????????",e);
????????}
????????catch(exception e)
????????",e);
????????}
????????finally
????????
????}
}程式輸出:
try ...
nullreferenceexception : system.nullreferenceexception: object reference not set to an instance of an object.
???at test.main()
finally ...
我們看到即使丟擲了異常,finally語句也被執行。try語句還可以和finally語句搭配構成try-finally語句。try-finally語句偵測到異常後,只是簡單地丟擲,並沒有捕捉。但在這種異常得到處理(被呼叫其方法的catch語句捕捉,或者到達main函式入口點被執行環境中斷)後,finally語句語句仍然執行。當然finally語句塊只能有乙個了,這是不言自明的。
???????我們在上面的**中用了throw語句來丟擲異常,這是怎麼回事呢?在我們的**設計中,遇到違背程式設計設定的條件,或異常的情況,我們常常要丟擲自己特定的異常。這時候throw語句就很有用了,我們來看下面的例子:
using system;
????public myexception (string message, exception inner) : base(message,inner)
???????
}public class myclass
????public static void mymethod()
????
????????catch (exception e)
????????
????}
}public class test
????????catch(exception e)
????????
????}
}程式輸出:
myexception: exception in mymethod ---> myexception: exception in exmethod
???at myclass.exmethod()
???at myclass.mymethod()
???--- end of inner exception stack trace ---
???at myclass.mymethod()
???at test.main()
myexception: exception in exmethod
???at myclass.exmethod()
???at myclass.mymethod()
在上面的例子,我們設計了自己的異常類myexception,並在自己的類設計中簡單地應用了這種異常類。測試程式中展示了它的處理,以及在多個方法的呼叫中異常的追蹤。其中e.getbaseexception()是呼叫system.exception的getbaseexception()方法,獲得引起異常e的最開始的那個異常,如果沒有,將返回e自己。system.exception的很多方法和屬性為我們提供了很好的對異常的描述和追蹤服務,它是我們應用異常,設計異常,認識異常的乙個很好的起點。
checked與 unchecked
???????對於因為整數型別參與算術操作和型別轉換時產生的「溢位異常」——system.overflowexception,在某些演算法來講不算真正的「異常」,相反這種溢位常常為程式所用。c#通過引入checked和unchecked關鍵字來控制這種特殊情況的需求。它們都可以加之於乙個語句塊前(如:checked),或者乙個算術表示式前(如:unchecked(x+y))。其中加checked標誌的語句或表示式,如果發生算術溢位,則丟擲system.overflowexception型別的異常。而unchecked標誌的發生算術溢位時,則不丟擲異常。下面是乙個演示示例:
using system;
class test
????????????catch(system.overflowexception e)
????????????
????????????finally
????????????
????????}
????????unchecked
????????
????????????catch(system.overflowexception e)
????????????
????????????finally
????????????
????????}
????}
}程式輸出:
system.overflowexception: arithmetic operation resulted in an overflow.
???at test.main()
01410065408
???????可以看到同樣的算術操作,用checked丟擲了溢位異常,而unchecked只是將溢位的位丟棄而得到剩下的32位組成的十進位制整數值。值得指出的是可以用「/checked」編譯器選項指定整個檔案的**為checked語義,如果沒有指定則預設為unchecked。如果同時在程式**中指定checked或unchecked標誌,又有了checked編譯器選項,則除了標誌為unchecked的**外,其餘的都有checked語義。
C 銳利體驗 第十六講 對映
c 銳利體驗 南京郵電學院李建忠 lijianzhong 263.第十六講對映 動態型別查詢 我們知道,c 編譯後的 pe檔案主要由 il 和元資料組成,元資料為 元件提供了豐富的自描述特性,它使得我們可以在 執行時獲知元件中的型別等重要的資訊。在 c 中這是通過一種稱作對映 reflection ...
sklearn第十七講 特徵選擇
sklearn.feature selection模組裡的類能被用來在樣本集上作特徵選擇 或者叫維數降低,改善估計量的準確性 在高維空間的表現。下面我們介紹幾種常用的特徵選擇方法。variancethreshold是乙個簡單的特徵選擇基準方法。它刪除所有方差小於某閾值的特徵。預設刪除所有0方差特徵,...
C 銳利體驗 第十講 介面 繼承與多型
第十講 介面 繼承與多型 介面 介面定義物件成員的合同,是現代元件程式設計不可缺少的一環。c 採用關鍵字 inte ce 來建立介面。介面作為一種型別,它也具有其他型別所共有的五種訪問修飾和new重定義修飾符。介面可以包含方法,屬性,事件,索引器四種成員,介面本身只能宣告這些成員,不必也不能提供這些...