程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Emit學習(3),emit學習

Emit學習(3),emit學習

編輯:關於.NET

Emit學習(3),emit學習


本來准備直接進入Dapper的, 但是昨天初步看了一下, 內容不少, Dapper不愧是一款成熟的框架, 裡面對各種情況的考慮, 很實用, 不過這也使得我短時間內看不完, 所以得等幾天了. 

那就先來看看循環和異常吧, 看IL跳轉的時候, 有一個標簽, 跳來跳去的, 在OpCodes裡面, 也是有對應的實現的.

一、示例

public static void Xunhuan(int num)
        {
            try
            {
                int sum = 0;
                if (num < 1)
                {
                    throw new Exception("num is less than 1");
                }
                for (int i = 1; i <= num; i++)
                {
                    sum += i;
                }
                Console.WriteLine("executed successfully : Sum = " + sum);
            }
            catch (Exception e)
            {
                Console.WriteLine("error happened : " + e.Message);
            }
        }

在調用Xunhuan()的時候, 傳入小於1的值時, 會拋出異常, 進入異常處理部分,  否則進入循環(此處為了演示, 使用循環, 否則應該使用算法計算結果), 求和. 結果我就不貼了.

 

二、OpCodes實現

static Action<int> action;
        static void Main(string[] args)
        {
            //定義一個動態方法
            var method = new DynamicMethod("Xunhuan", null, new Type[] { typeof(int) });
            ILGenerator IL = method.GetILGenerator();

            //定義標簽
            var label1 = IL.DefineLabel();  
            var xunLabel = IL.DefineLabel();
            var endLabel = IL.DefineLabel();

            //定義本地變量
            var sum = IL.DeclareLocal(typeof(int));
            var i = IL.DeclareLocal(typeof(int));

            IL.Emit(OpCodes.Ldc_I4_0);
            IL.Emit(OpCodes.Stloc_0); //sum = 0

            IL.Emit(OpCodes.Ldc_I4_1);
            IL.Emit(OpCodes.Stloc_1); // i = 1
            IL.Emit(OpCodes.Ldstr, "enter number : num = ");
            IL.Emit(OpCodes.Ldarg_0);
            //實現方式一 裝箱
            IL.Emit(OpCodes.Box, typeof(int));   //裝箱
            IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(object) }));
            IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));

            Label tryLabel = IL.BeginExceptionBlock(); //try
            IL.Emit(OpCodes.Ldarg_0);  //num
            IL.Emit(OpCodes.Ldc_I4_1); // 1
            IL.Emit(OpCodes.Bge, label1); //num >= 1 -> label1, 注: try裡面的跳轉, 不能跳出try語句, 只能在內部
            
            IL.Emit(OpCodes.Ldstr, "num is less than 1");
            IL.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new Type[] { typeof(string) })); //new Exception();
            IL.Emit(OpCodes.Throw); //throw

            IL.MarkLabel(label1);
            IL.Emit(OpCodes.Ldloc_1); //i
            IL.Emit(OpCodes.Ldarg_0); //num
            IL.Emit(OpCodes.Bgt, xunLabel); // i > num -> endLabel

            IL.Emit(OpCodes.Ldloc_0);
            IL.Emit(OpCodes.Ldloc_1);
            IL.Emit(OpCodes.Add);
            IL.Emit(OpCodes.Stloc_0); // sum += i;

            IL.Emit(OpCodes.Ldloc_1);
            IL.Emit(OpCodes.Ldc_I4_1);
            IL.Emit(OpCodes.Add);
            IL.Emit(OpCodes.Stloc_1); //i+=1;
            IL.Emit(OpCodes.Br_S, label1);

            IL.MarkLabel(xunLabel);
            IL.Emit(OpCodes.Ldstr, "executed successfully : Sum = ");
            IL.Emit(OpCodes.Ldloc_0);
            //實現方式二 調用Convert.ToString(int num)方法
            IL.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) }));
            IL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));
            IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }));

            IL.MarkLabel(endLabel);
            IL.Emit(OpCodes.Nop);

            IL.BeginCatchBlock(typeof(Exception)); //catch
            IL.Emit(OpCodes.Callvirt, typeof(Exception).GetMethod("get_Message"));
            IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            IL.EndExceptionBlock(); //end
          
            IL.Emit(OpCodes.Ret);

            action = (Action<int>)method.CreateDelegate(typeof(Action<int>)); //此處通過委托的方式來調動方法, 而不再是保存成dll文件了

            Console.WriteLine("-------------正常執行---------------");
            action.Invoke(10);
            Console.WriteLine("-------------異常執行---------------");
            action.Invoke(-10);
            Console.ReadKey();
        }

實現的方式並不是唯一的, 我寫的這個方法, 並不是最簡的. 下面貼出reflector反編譯的IL代碼, 與我寫的這個還是有不少不同的.

   .method public hidebysig static void Xunhuan(int32 num) cil managed
    {
        .maxstack 2
        .locals init (
            [0] int32 num2,
            [1] int32 num3,
            [2] class [mscorlib]System.Exception exception,
            [3] bool flag)
        L_0000: nop 
        L_0001: nop 
        L_0002: ldc.i4.0 
        L_0003: stloc.0 
        L_0004: ldarg.0 
        L_0005: ldc.i4.1 
        L_0006: clt 
        L_0008: ldc.i4.0 
        L_0009: ceq 
        L_000b: stloc.3 
        L_000c: ldloc.3 
        L_000d: brtrue.s L_001b
        L_000f: nop 
        L_0010: ldstr "num is less than 1"
        L_0015: newobj instance void [mscorlib]System.Exception::.ctor(string)
        L_001a: throw 
        L_001b: ldc.i4.1 
        L_001c: stloc.1 
        L_001d: br.s L_0029
        L_001f: nop 
        L_0020: ldloc.0 
        L_0021: ldloc.1 
        L_0022: add 
        L_0023: stloc.0 
        L_0024: nop 
        L_0025: ldloc.1 
        L_0026: ldc.i4.1 
        L_0027: add 
        L_0028: stloc.1 
        L_0029: ldloc.1 
        L_002a: ldarg.0 
        L_002b: cgt 
        L_002d: ldc.i4.0 
        L_002e: ceq 
        L_0030: stloc.3 
        L_0031: ldloc.3 
        L_0032: brtrue.s L_001f
        L_0034: ldstr "executed successfully : Sum = "
        L_0039: ldloc.0 
        L_003a: box int32
        L_003f: call string [mscorlib]System.String::Concat(object, object)
        L_0044: call void [mscorlib]System.Console::WriteLine(string)
        L_0049: nop 
        L_004a: nop 
        L_004b: leave.s L_0068
        L_004d: stloc.2 
        L_004e: nop 
        L_004f: ldstr "error happened : "
        L_0054: ldloc.2 
        L_0055: callvirt instance string [mscorlib]System.Exception::get_Message()
        L_005a: call string [mscorlib]System.String::Concat(string, string)
        L_005f: call void [mscorlib]System.Console::WriteLine(string)
        L_0064: nop 
        L_0065: nop 
        L_0066: leave.s L_0068
        L_0068: nop 
        L_0069: ret 
        .try L_0001 to L_004d catch [mscorlib]System.Exception handler L_004d to L_0068
    }

 以前總是懶, 對於新的知識, 都是看看, 看懂就成, 但是在實際寫的過程中, 會碰到很多看不會遇到的問題, 編碼還真不是看看就能寫好的, 好記性不如爛筆頭, 還是得自己一行一行敲一下, 才能發現裡面的問題.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved