.NET(C#):Emit創(chuàng)建異常處理的方法
目錄
Emit異常處理流程
顯示Exception對(duì)象的Message屬性
返回目錄
Emit異常處理流程
來(lái)看這種C#異常處理代碼:
static void doo(Exception e)
{
try
{
throw e;
}
catch (ApplicationException ex)
{
Console.WriteLine("捕獲ApplicationException");
}
catch
{
Console.WriteLine("捕獲Exception");
}
finally
{
Console.WriteLine("finally塊");
}
}
我們將用反射Emit創(chuàng)建一個(gè)這樣的方法。
其實(shí)IL中的異常處理代碼還是比較復(fù)雜的,你可以在Reflector下看看異常處理的IL代碼。不過(guò)好在ILGenerator類提供了一些方便的方法來(lái)創(chuàng)建異常處理代碼。
基本套路就是用如下ILGenerator的方法:
BeginExceptionBlock方法來(lái)開(kāi)始異常處理代碼(相當(dāng)于try)。
之后的代碼可以用Opcodes.Throw來(lái)拋出異常,或者調(diào)用其他可以拋出異常的代碼。
接著用BeginCatchBlock方法來(lái)開(kāi)始一個(gè)Catch塊,該方法可以指定catch需要捕獲的異常類型,另外有一點(diǎn)需要注意的是凡是進(jìn)入該catch方法,邏輯棧上會(huì)有相應(yīng)類型的異常對(duì)象。 同時(shí),這里也可以用Opcodes.Rethrow來(lái)重新拋出異常。
最后BeginFinallyBlock方法開(kāi)始一個(gè)finally塊。 (這里不需要手動(dòng)加Opcodes.Leave)
當(dāng)全部異常處理代碼寫(xiě)完后,加上EndExceptionBlock方法來(lái)結(jié)束整塊異常處理代碼塊。
注意方法最后還是必須要加IL的ret指令的(Opcodes.Ret),否則CLR無(wú)法運(yùn)行此方法。
來(lái)看代碼:
//+ using System.Reflection;
//+ using System.Reflection.Emit;
static void Main(string[] args)
{
var dm = GetMethod();
dm.Invoke(null, new object[] { new ApplicationException() });
dm.Invoke(null, new object[] { new Exception() });
}
static DynamicMethod GetMethod()
{
var dm = new DynamicMethod("", null, new Type[] { typeof(Exception) });
var ilgen = dm.GetILGenerator();
//try {
ilgen.BeginExceptionBlock();
//加載第一個(gè)參數(shù),并throw
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Throw);
ilgen.BeginCatchBlock(typeof(ApplicationException));
//清空棧上的異常對(duì)象
ilgen.Emit(OpCodes.Pop);
ilgen.EmitWriteLine("捕獲ApplicationException");
ilgen.BeginCatchBlock(typeof(Exception));
//清空棧上的異常對(duì)象
ilgen.Emit(OpCodes.Pop);
ilgen.EmitWriteLine("捕獲Exception");
ilgen.BeginFinallyBlock();
ilgen.EmitWriteLine("finally塊");
//結(jié)束整個(gè)處理塊
ilgen.EndExceptionBlock();
ilgen.Emit(OpCodes.Ret);
return dm;
}
輸出:
捕獲ApplicationException
finally塊
捕獲Exception
finally塊
返回目錄
顯示Exception對(duì)象的Message屬性
上面的代碼并沒(méi)有顯示Exception對(duì)象的Message屬性,上面主要是介紹Emit異常處理的流程,下面來(lái)看看怎樣顯示Message屬性,如果是直接輸出當(dāng)然簡(jiǎn)單了,不過(guò)如果用到Console.WriteLine的格式字符串的話,需要在catch代碼塊中用一個(gè)臨時(shí)變量。
如下代碼:
//+ using System.Reflection;
//+ using System.Reflection.Emit;
static void Main(string[] args)
{
var dm = GetMethod();
dm.Invoke(null, new object[] { new Exception("來(lái)自Mgen!") });
}
static DynamicMethod GetMethod()
{
var dm = new DynamicMethod("", null, new Type[] { typeof(Exception) });
var ilgen = dm.GetILGenerator();
//try {
ilgen.BeginExceptionBlock();
//加載第一個(gè)參數(shù),并throw
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Throw);
ilgen.BeginCatchBlock(typeof(Exception));
//臨時(shí)變量 和 需要的反射信息
var exp = ilgen.DeclareLocal(typeof(Exception));
var msg = typeof(Exception).GetProperty("Message").GetGetMethod();
var output = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object) });
//保存異常對(duì)象到臨時(shí)變量exp
ilgen.Emit(OpCodes.Stloc, exp);
//格式字符串進(jìn)棧
ilgen.Emit(OpCodes.Ldstr, "錯(cuò)誤信息: {0}");
//加載臨時(shí)變量
ilgen.Emit(OpCodes.Ldloc, exp);
//獲取Message屬性
ilgen.Emit(OpCodes.Callvirt, msg);
//調(diào)用有格式字符串的Console.WriteLine
ilgen.Emit(OpCodes.Call, output);
//結(jié)束整個(gè)處理塊
ilgen.EndExceptionBlock();
ilgen.Emit(OpCodes.Ret);
return dm;
}
輸出:
錯(cuò)誤信息: 來(lái)自Mgen!
相關(guān)文章
Unity向量按照某一點(diǎn)進(jìn)行旋轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了Unity向量按照某一點(diǎn)進(jìn)行旋轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01C# SendMail發(fā)送郵件功能實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了C# SendMail發(fā)送郵件功能實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06C#基礎(chǔ)知識(shí)之base關(guān)鍵字介紹
本文主要介紹base關(guān)鍵字的使用方法,base關(guān)鍵字可以調(diào)用基類重寫(xiě)的方法,可以調(diào)用基類的構(gòu)造方法,還可以在EntityFramework中使用,下面一一介紹。2016-04-04C#中WebBrowser.DocumentCompleted事件多次調(diào)用問(wèn)題解決方法
這篇文章主要介紹了C#中WebBrowser.DocumentCompleted事件多次調(diào)用問(wèn)題解決方法,本文講解了3種情況和各自情況的解決方法,需要的朋友可以參考下2015-01-01C# BackgroundWorker組件學(xué)習(xí)入門(mén)介紹
一個(gè)程序中需要進(jìn)行大量的運(yùn)算,并且需要在運(yùn)算過(guò)程中支持用戶一定的交互,為了獲得更好的用戶體驗(yàn),使用BackgroundWorker來(lái)完成這一功能2013-10-10詳解C#的設(shè)計(jì)模式編程之抽象工廠模式的應(yīng)用
這篇文章主要介紹了C#的設(shè)計(jì)模式編程之抽象工廠模式的應(yīng)用,注意區(qū)分一下簡(jiǎn)單工廠模式、工廠方法模式和抽象工廠模式概念之間的區(qū)別,需要的朋友可以參考下2016-02-02C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn)
這篇文章介紹了C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01