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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...