標籤:

所有CLR開發人員都應該了解的關於運行時異常的知識(中)

不捕捉某一個異常

常常有這種情況,代碼不需要捕捉異常,但需要執行一些清理或者修正操作。雖然不總是,支持物(holders)經常用在這種場景里。在支持物(holders)不適用的情況里,CLR提供了兩個「finally」塊的變種。

EX_TRY_FOR_FINALLY

當需要在代碼退出時執行修正操作時,一個finally塊就比較合適。在CLR里有一系列的宏來實現try/finally:

EX_TRY_FOR_FINALLYn // codenEX_FINALLYn // exit and/or backout codenEX_END_FINALLYn

注意:EX_TRY_FOR_FINALLY是基於SEH(Windows操作系統異常處理機制),而不是C++的異常處理機制。C++編譯器不允許在一個函數里混合使用SEH和C++異常處理機制。有自動析構函數的局部變數要求C++異常處理機制以執行其析構函數。因此,使用了EX_TRY_FOR_FINALLY宏的函數不能同時使用EX_TRY,也不能有使用了自動析構函數的局部變數。

EX_HOOK

經常有這種情況,只在某種異常拋出的時候需要執行修正代碼。對這些情況,EX_HOOK跟EX_FINALLY很類似,但是「勾子(hook)」子句只在有異常的時候執行。異常會自動在退出「勾子」子句之前再次拋出。

EX_TRYn // codenEX_HOOKn // code to run when an exception escapes the 「code」 block.nEX_END_HOOKn

這個結構比簡單的EX_CATCH配上EX_RETHROW塊更好一些,因為其可以捕捉堆棧溢出異常(並向上展開堆棧),並再次拋出一個新的堆棧溢出異常。

拋出異常

在CLR里拋出異常其實就是下面的函數調用:

COMPlusThrow ( < args > )n

有很多重載函數,但思路基本上就是向COMPlusThrow傳入某個異常作為參數。異常類型由Rexcep.h中的一系列宏生成,如kAmbiguousMatchException, kApplicationException等類型。(重載函數)的其他參數指定資源和替代性文字。可以參考報告了類似異常的代碼來選擇異常類型。

以下是一些預定義的異常變種:

COMPlusThrowOOM();

最終調用ThrowOutOfMemory()函數,其拋出C++的OOM(內存不足)異常。它拋出一個預先創建的異常,因為不能在內存不足的情況下再找出內存創建這個異常!

當獲取這個異常對應的託管異常時,CLR首先會嘗試分配一個新託管對象[1],如果失敗的話,那麼就返回一個預先分配的,全局共享的內存不足異常對象。

[1] 畢竟,如果申請分配2G大小的數組失敗,申請一個小對象還是可以試試的。

COMPlusThrowHR(HRESULT 問題HR);

如果你有IErrorInfo的話,有很多重載可用。還有一些驚人複雜的代碼來指出一個HRESULT值對應哪種異常:

COMPlusThrowWin32(); / COMPlusThrowWin32(hr);

基本上是從Win32錯誤返回值拋出異常:HRESULT_FROM_WIN32(GetLastError())

COMPlusThrowSO();

拋出一個堆棧溢出(SO)異常。注意這個不是一個硬性的堆棧溢出,只是在可能導致硬性堆棧溢出的時候拋出的異常。

跟內存不足異常(OOM)類似,其拋出一個預先分配的C++堆棧溢出異常。跟OOM不同,當獲取託管異常對象時,CLR總是返回預先分配的,全局共享的堆棧溢出異常對象。

COMPlusThrowArgumentNull()

拋出「參數不能為空」異常的輔助函數。

COMPlusThrowArgumentOutOfRange()

如名所示。

COMPlusThrowArgumentException()

另一個無效參數相關的異常。

COMPlusThrowInvalidCastException(thFrom, thTo)

傳入強制轉換的源類型和目的類型,這個函數可以返回一個相當不錯的異常消息。

EX_THROW

這個是非常底層的拋出異常的函數,普通代碼基本不用。很多COMPlusThrowXXX函數在內部使用EX_THROW,跟其它特定的ThrowXXX函數類似。最好少用EX_THROW,盡量使用封裝好的函數以隱藏異常機制的細節。當然,如果沒有合適的Throw函數可用,使用EX_THROW是可以接受的。

這個宏接受兩個參數,要拋出的異常類型(C++ Exception類的某些子類),和用括弧括起來的傳遞給該類型異常的構造函數的參數列表。

推薦閱讀:

CLR 相比 JVM有哪些先進之處?
程序集什麼玩意?我知道其表現形式為dll和exe,但是exe不是直接執行的文件嗎?而dll只是類庫,供exe調用代碼?
RyuJIT為什麼比JIT64編譯速度快?
.NET CLR怎麼保證執行正確的unsafe代碼不掛掉?

TAG:NET | CLR |