IL初步瞭解

来源:http://www.cnblogs.com/lflyq/archive/2016/12/16/6186049.html
-Advertisement-
Play Games

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


 

一、概述:

     近來也是在看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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言 在WPF編程中,有時候我們使用DataGrid會需要在一個DataColumn中既有TextBox,也要有ComboBox或者TextBlock等其他數據顯示樣式。 這個時候我們就需要DataGridTemplateColumn去自定義我們的Column樣式,通過數據類型去判斷該信息是以T ...
  • 在上一篇多線程(基礎篇2)中,我們主要講述了確定線程的狀態、線程優先順序、前臺線程和後臺線程以及向線程傳遞參數的知識,在這一篇中我們將講述如何使用C#的lock關鍵字鎖定線程、使用Monitor鎖定線程以及線程中的異常處理。 九、使用C#的lock關鍵字鎖定線程 1、使用Visual Studio 2 ...
  • 建立窗體的名稱修改為:Form_HoverTree文後附有源碼下載。主要代碼: 效果圖: 可以看出,這個窗體為自定義形狀的窗體,沒有標題欄。具體參考:http://hovertree.com/h/bjaf/52nadvt4.htm 源碼下載: http://hovertree.com/h/bjaf/ ...
  • 委托是個說爛了的話題,但是依舊有好多人不知道為什麼要在C 中使用委托,最近有朋友也問到我這個問題,所以舉例些場景,以供那些知道怎麼聲明委托、怎麼調用卻不知道為什麼要用的朋友一些參考,當然也是希望驗證下自己的理解是否正確。 如何聲明一個委托 委托使用關鍵字delegate,從外形上看和一個沒有方法體的 ...
  • 什麼是工作流? 工作流(Workflow),是對工作流程及其各操作步驟之間業務規則的抽象、概括、描述。BPM:是Business Process Management的英文字母縮寫.即業務流程管理,是一套達成企業各種業務環節整合的全面管理模式。 工作流軟體,顧名思義,就是業務信息數據在多個環節模塊之 ...
  • 1 public class BaseDAL 2 { 3 string strConn = ""; 4 public BaseDAL(string connString) 5 { 6 strConn = connString; 7 } 8 9 #region 通用增刪改查 10 #re... ...
  • 編程思想其本質是解決問題的思考,不過此時要站在電腦的角度思考如何解決? < 學習網站 > 博客園cnblogs --有優質博文 CSND --有優質討論 book.51cto.com //線上書籍 infoq //技術大牛講壇 it-ebooks.info //最新免費技術書籍下載 w3cscho ...
  • 2016-12-17 無意間看到了關於C#線程的講解。經過一下午的學習後,慢慢的對線程也有了一定的理解。這裡講解的是最基礎的內容,包括線程的創建、睡眠、等待、終止。 實驗環境:Visual studio 2010. 使用語言:C# 內容:創建、睡眠、等待、中止線程 1.創建新線程對象 Thread ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...