.NET(C#):Emit建立異常處理代碼

來源:互聯網
上載者:User

目錄

  • Emit異常處理流程
  • 顯示Exception對象的Message屬性

 

 

返回目錄

Emit異常處理流程

來看這種C#異常處理代碼:

static void doo(Exception e)

{

    try

    {

        throw e;

    }

    catch (ApplicationException ex)

    {

        Console.WriteLine("捕獲ApplicationException");

    }

    catch

    {

        Console.WriteLine("捕獲Exception");

    }

    finally

    {

        Console.WriteLine("finally塊");

    }

}

 

我們將用反射Emit建立一個這樣的方法

其實IL中的異常處理代碼還是比較複雜的,你可以在Reflector下看看異常處理的IL代碼。不過好在ILGenerator類提供了一些方便的方法來建立異常處理代碼。

 

基本套路就是用如下ILGenerator的方法:

  • BeginExceptionBlock方法來開始異常處理代碼(相當於try)。
  • 之後的代碼可以用Opcodes.Throw來拋出異常,或者調用其他可以拋出異常的代碼。
  • 接著用BeginCatchBlock方法來開始一個Catch塊,該方法可以指定catch需要捕獲的異常類型,另外有一點需要注意的是凡是進入該catch方法,邏輯棧上會有相應類型的異常對象。 同時,這裡也可以用Opcodes.Rethrow來重新拋出異常。
  • 最後BeginFinallyBlock方法開始一個finally塊。 (這裡不需要手動加Opcodes.Leave)
  • 當全部異常處理代碼寫完後,加上EndExceptionBlock方法來結束整塊異常處理代碼塊。
  • 注意方法最後還是必須要加IL的ret指令的(Opcodes.Ret),否則CLR無法運行此方法。

 

來看代碼:

//+ 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();

 

    //載入第一個參數,並throw

    ilgen.Emit(OpCodes.Ldarg_0);

    ilgen.Emit(OpCodes.Throw);

 

    ilgen.BeginCatchBlock(typeof(ApplicationException));

    //清空棧上的異常對象

    ilgen.Emit(OpCodes.Pop);

    ilgen.EmitWriteLine("捕獲ApplicationException");

 

    ilgen.BeginCatchBlock(typeof(Exception));

    //清空棧上的異常對象

    ilgen.Emit(OpCodes.Pop);

    ilgen.EmitWriteLine("捕獲Exception");

 

    ilgen.BeginFinallyBlock();

    ilgen.EmitWriteLine("finally塊");

 

    //結束整個處理塊

    ilgen.EndExceptionBlock();

 

    ilgen.Emit(OpCodes.Ret);

 

    return dm;

}

 

輸出:

捕獲ApplicationException

finally塊

捕獲Exception

finally塊

 

 

返回目錄

顯示Exception對象的Message屬性

上面的代碼並沒有顯示Exception對象的Message屬性,上面主要是介紹Emit異常處理的流程,下面來看看怎樣顯示Message屬性,如果是直接輸出當然簡單了,不過如果用到Console.WriteLine的格式字串的話,需要在catch代碼塊中用一個臨時變數。

 

如下代碼:

//+ using System.Reflection;

//+ using System.Reflection.Emit;

static void Main(string[] args)

{

    var dm = GetMethod();

    dm.Invoke(null, new object[] { new Exception("來自Mgen!") });

}

 

static DynamicMethod GetMethod()

{

    var dm = new DynamicMethod("", null, new Type[] { typeof(Exception) });

    var ilgen = dm.GetILGenerator();

 

    //try {

    ilgen.BeginExceptionBlock();

 

    //載入第一個參數,並throw

    ilgen.Emit(OpCodes.Ldarg_0);

    ilgen.Emit(OpCodes.Throw);

 

    ilgen.BeginCatchBlock(typeof(Exception));

    //臨時變數 和 需要的反射資訊

    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) });

 

    //儲存異常對象到臨時變數exp

    ilgen.Emit(OpCodes.Stloc, exp);

    //格式字串進棧

    ilgen.Emit(OpCodes.Ldstr, "錯誤資訊: {0}");

    //載入臨時變數

    ilgen.Emit(OpCodes.Ldloc, exp);

    //擷取Message屬性

    ilgen.Emit(OpCodes.Callvirt, msg);

    //調用有格式字串的Console.WriteLine

    ilgen.Emit(OpCodes.Call, output);

 

    //結束整個處理塊

    ilgen.EndExceptionBlock();

 

    ilgen.Emit(OpCodes.Ret);

 

    return dm;

}

 

輸出:

錯誤資訊: 來自Mgen!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.