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

IL初步了解,初步了解英文

編輯:關於.NET

IL初步了解,初步了解英文


 

一、概述:

     近來也是在看AOP方面的東西,了解到Emit可以實現。之前對Emit的了解也就是停留在Reflector針對方法反編譯出來的部分指令。就用這次機會學習下Emit也用這篇隨筆記錄下學習的過程。某些我也不了解的地方也希望各位了解的朋友指導下。

     學習前可以先了解下Opcodes

二、工具

1、vs2015

2、.NET Reflector 9.0

三、入門示例

1、輸出Hello World

C#代碼

        static void Main(string[] args)
        {
            Console.WriteLine("Hello world!");
        }
View Code

反編譯獲取到的IL代碼

Emit實現代碼

        public void HellowWorld()
        {
            //定義Hellow方法沒有返回值沒有參數
            DynamicMethod helloWorldMethod = new DynamicMethod("HellowWorld", null, null);

            //創建IL,動態生成代碼
            ILGenerator IL = helloWorldMethod.GetILGenerator();
            //將輸出推送到堆棧上
            IL.Emit(OpCodes.Ldstr, "Hello World!");
            //執行Console.WriteLine
            IL.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            //方法結束
            IL.Emit(OpCodes.Ret);
            HelloWordDelegate Method = (HelloWordDelegate)helloWorldMethod.CreateDelegate(typeof(HelloWordDelegate));
            Method();
        }
View Code

  委托調用過程中。如果有參數會提示“操作可能破壞運行時穩定性”。(沒弄清楚)

四、構建程序集

1、下面通過構建一個類裡面包含兩個方法來做實例

        public int Add(int a, int b)
        {
            return a + b;
        }

        public string AddList(string[] array)
        {
            string result = string.Empty;
            for (int i = 0; i < array.Length; i++)
            {
                result = result + array[i];
            }
            return result;
        }
View Code

2、看下兩個方法反編譯出來的IL代碼

下面我們來看看這段IL到底是如何實現的

●L0000到L0009:將string.Empty賦值給自定義變量resultName,加載整數0,L0009跳轉到L001b執行
●L001b到L0027:加載1處索引值,加載參數1(靜態從0開始),Ldlen將數組數目從0開始推送到堆棧上,對比兩個數值的大小,(將對比結果存儲到索引2處,然後再取出(這步實現中可省略)),然後跳轉L_000b執行
●L000b到L001a:加載0處索引值,加載參數1,Ldelem_Ref用來加載string類型元素,執行string.concat方法,將值存儲到索引0處,加載索引1處值,加載整數1,兩值相加,將值存儲到索引0處
●L002a結束返回

3、下面我們通過Emit代碼來實現

        public void GenerateAssembly()
        {
            string name = "IL.Dynamic";
            string fileName = string.Format("{0}.dll", name);

            //構建程序集
            AssemblyName assemblyName = new AssemblyName(name);
            //應用程序集域
            AppDomain domain = AppDomain.CurrentDomain;
            //實例化一個AssemblyBuilder對象來實現動態程序集的構建
            AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

            //定義模塊(不加filename為瞬態模塊,不持久)
            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name);

            //定義類型
            TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public);

            //定義一個Add方法進行簡單的相加
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("Add", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(int), typeof(int) });

            //IL實現
            ILGenerator IL = methodBuilder.GetILGenerator();
            IL.Emit(OpCodes.Ldarg_1);
            IL.Emit(OpCodes.Ldarg_2);
            IL.Emit(OpCodes.Add);
            IL.Emit(OpCodes.Ret);


            //定義一個AddList字符串用for拼接方法
            MethodBuilder method2Builder = typeBuilder.DefineMethod("AddList", MethodAttributes.Public| MethodAttributes.Static, typeof(string), new Type[] { typeof(string[]) });
            FieldBuilder fieldName = typeBuilder.DefineField("resultName", typeof(string), FieldAttributes.Private | FieldAttributes.Static);
            ILGenerator addIL = method2Builder.GetILGenerator();

            //用來保存求和結果的局部變量
            LocalBuilder resultStr = addIL.DeclareLocal(typeof(String));
            ////循環中使用的局部變量
            LocalBuilder i = addIL.DeclareLocal(typeof(Int32));

            Label concatLabel = addIL.DefineLabel();
            Label LoopLabel = addIL.DefineLabel();

            //設置string result = string.Empty;
            addIL.Emit(OpCodes.Ldsfld, fieldName);
            addIL.Emit(OpCodes.Stloc_0);
            //設置i=0
            addIL.Emit(OpCodes.Ldc_I4_0);
            addIL.Emit(OpCodes.Stloc_1);
            addIL.Emit(OpCodes.Br, concatLabel);

            //進入循環體
            addIL.MarkLabel(LoopLabel);
            addIL.Emit(OpCodes.Ldloc_0);
            //參數指定靜態從0開始
            addIL.Emit(OpCodes.Ldarg_0);
            addIL.Emit(OpCodes.Ldloc_1);
            //Ldelem_Ref用來加載string 類型元素
            addIL.Emit(OpCodes.Ldelem_Ref);
            addIL.Emit(OpCodes.Call, typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }));
            addIL.Emit(OpCodes.Stloc_0);
            addIL.Emit(OpCodes.Ldloc_1);

            //i++
            addIL.Emit(OpCodes.Ldc_I4_1);
            addIL.Emit(OpCodes.Add);
            addIL.Emit(OpCodes.Stloc_1);

            addIL.MarkLabel(concatLabel);

            addIL.Emit(OpCodes.Ldloc_1);
            addIL.Emit(OpCodes.Ldarg_0);
            addIL.Emit(OpCodes.Ldlen);
            addIL.Emit(OpCodes.Conv_I4);
            //Clt比較兩值大小
            addIL.Emit(OpCodes.Clt);
            addIL.Emit(OpCodes.Brtrue_S, LoopLabel);

            addIL.Emit(OpCodes.Ldloc_0);
            addIL.Emit(OpCodes.Ret);



            Type type = typeBuilder.CreateType();
            assemblyBuilder.Save(fileName);

            int[] ints = new int[] { 1, 2, 3, 4 };
            string[] array = new string[] { "a", "b", "c" };
            object ob = Activator.CreateInstance(type);
            var result = type.GetMethod("Add").Invoke(ob, new object[] { 8, 9 });
            var result1 = type.GetMethod("AddList").Invoke(ob, new object[] { array });
        }
View Code

3.1、AssemblyBuilderAccess

Run 可以執行但不能保存 Save 保存但不能執行 RunAndSave 可以執行並保存 ReflectionOnly 只反射上下文中加載

 

 

 

 

4、運行輸出

4.1、生成文件

借助工具反編譯查看IL生成的C#代碼

4.2、運行結果

 通過這個實例對IL可以有了比較基礎的了解,在之後的學習中再慢慢喝大家進行交流。項目下載System.IL

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