-
異常
-
成員沒有完成它的名稱所宣稱的行動
-
-
C#中的異常處理使用
-
public static void ExceptionControl()
{
string a = null;
try
{
a.Contains("Str");
}
catch (NullReferenceException e)
{
Console.WriteLine("Null Reference Exception Caught!");
}
catch
{
Console.WriteLine("Some Exception Caught");
}
finally
{
Console.WriteLine("Exception Test Finished");
}
} -
try塊
-
應包含以下類型的代碼
-
需要執行的資源清理操作的代碼
-
需要從異常中恢復的代碼
-
可能會拋出異常的代碼
-
-
一個try塊至少要有一個關聯的catch塊/finally塊
-
-
catch塊
-
響應一個異常需要執行的代碼
-
可以有0個或多個catch塊
-
如果try塊代碼沒有造成異常的拋出,則永遠不會執行任何catch塊,直接執行finally塊(如有)
-
catch塊後的圓括號中的表達式為「捕捉類型」
-
該類型必須派生自System.Exception
-
如果只有catch關鍵字,沒有指定任何捕捉類型,代表捕捉除了上面catch塊指定了的具體捕捉類型以外的捕捉類型
-
如果在捕捉類型後指定一個變量,該變量將引用拋出的System.Exception派生對象
-
-
CLR自上而下搜索匹配的catch塊,因此越是具體的(從System.Exception派生得越遠)的異常,應最先被捕捉
-
如果搜索過後,沒有任何捕捉類型與拋出的異常匹配,CLR會去調用棧更高的一層嘗試搜索匹配的異常捕捉類型
-
一旦找到,就會執行「內層」的所有finally塊代碼
-
-
-
-
finally塊
-
保證會執行
-
一般執行try塊行動所要求的資源清理操作
-
public static void ReadData(string path)
{
FileStream fs = null;
try
{
fs = new FileStream(path, FileMode.Open);
}
catch (IOException) { }
finally
{
if(fs != null)
{
fs.Close();
}
}
} -
如在該段代碼中,無論try中的代碼有沒有拋出異常,文件保證會被finally中的代碼所關閉
-
否則,如果文件流關閉的代碼放了在finally塊之後的地方,那當try塊拋出異常後,finally塊後的語句沒法被執行,文件流也就無法被關閉
-
因此,C#編譯器看到一些必須進行清理的代碼,會自動生成try/finally塊
-
lock/using/foreach/定義析構器
-
-
-
一個try塊最多只能關聯一個finally塊
-
-
System.Exception
-
雖然CLR允許異常拋出任何類型的實例,但Microsoft定義了System.Exception類,並規定所有CLS相容的語言都必須能拋出和捕捉派生自該類型的異常
-
派生自System.Exception的異常類型被認為是CLS相容的
-
C#也只允許拋出CLS相容的異常
-
-
System.Exception提供了一個唯讀的StackTrace屬性
-
catch塊可讀取該屬性來獲取一個stack trace,它描述了異常發生前調用了哪些方法
-
訪問該屬性會調用CLR的代碼
-
一個異常拋出時,CLR在內部記錄throw指令的位置
-
-
約束執行區域(CER)
-
CER是必須對錯誤有適應力的代碼塊
-
在拋出了非預期的異常時維護狀態非常有用
-
-
RuntimeHelpers.PrepareConstrainedRegions
-
public static void Demo()
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Console.WriteLine("In Try");
}
finally
{
Type2.M();
}
}
public class Type2
{
static Type2()
{
Console.WriteLine("Type2 ctor called");
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static void M() { }
} -
JIT編譯器如果發現在一個try塊前調用了RuntimeHelpers.PrepareConstrainRegions,就會提前編譯與try關聯的catch和finally塊中的代碼
-
但是,在catch/finally塊裡被調用的方法,必須應用ReliabilityContract特性。且傳遞了Consistency.WillNotCorruptState/Consistency.MayCorruptInstance枚舉值
-
-
代碼協定
-
代碼協定提供了直接在代碼中聲明代碼設計決策的一種方式
-
前條件:驗證實參
-
後條件:方法因返回/拋出異常而終止時,對狀態進行驗證
-
對象不變性:在對象生命期內確保對象的字段的良好狀態
-
-
核心為靜態類:System.Diagnostics.Contracts.Contract
參考書目
- 《CLR via C#》(第4版) Jeffrey Richter