`

Emit学习之旅:例子 (整理中...)

    博客分类:
  • C#
阅读更多

---------------------------------------------------------------------------------------------------

例子 1: 最简单的语句

       public void Test1()
        {
            Console.WriteLine("aaaa");
        }

生成的IL:

.method public hidebysig instance void Test1() cil managed
    {
        .maxstack 8
        L_0000: nop 
        L_0001: ldstr "aaaa"
        L_0006: call void [mscorlib]System.Console::WriteLine(string)
        L_000b: nop 
        L_000c: ret 
    }

使用ILGenerator的Emit方法,改写为

            ILGenerator il = methodBuilder.GetILGenerator();

            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldstr, "aaaa");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ret);

 

---------------------------------------------------------------------------------------------------

例子 2 

public void Test1()
        {
            string str = "aaaa";
            Console.WriteLine(str);
        }

 生成的IL:

.method public hidebysig instance void Test1() cil managed
    {
        .maxstack 1
        .locals init (
            [0] string str)
        L_0000: nop 
        L_0001: ldstr "aaaa"
        L_0006: stloc.0 
        L_0007: ldloc.0 
        L_0008: call void [mscorlib]System.Console::WriteLine(string)
        L_000d: nop 
        L_000e: ret 
    }

 使用ILGenerator的Emit方法,改写为:

            var str = il.DeclareLocal(typeof(string));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldstr, "aaaa");
            il.Emit(OpCodes.Stloc, str);
            il.Emit(OpCodes.Ldloc, str);
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ret);

 

---------------------------------------------------------------------------------------------------

例子 3 : 运算

public void PrintCube(int i)
        {
            int cube = i * i * i;
            Console.WriteLine(cube);
        }

 生成的IL:

.method public hidebysig instance void PrintCube(int32 i) cil managed
{
    .maxstack 2
     // 在 .locals 部分声明所有的局部变量。
    .locals init (
        [0] int32 cube)    // 第一个名局部变量,int 型,名为 cube。索引从 0 开始。
    L_0000: nop  // no operation.
    L_0001: ldarg.1 // load argument 第一个方法参数入栈,比如“3”。索引号 从 1 开始,而不是从 0 开始。
    L_0002: ldarg.1 // 再次向堆栈压入第一个方法参数,又一个“3”。
    L_0003: mul // multiply 计算堆栈最顶上两个数的乘积 3×3,并把结果入栈,即堆栈最顶部是 9 了。
    L_0004: ldarg.1 // 再次压入第一个方法参数“3”。
    L_0005: mul // 堆栈最顶上是“3”,第二是“9”,计算 3×9,此时 27 入栈。
    L_0006: stloc.0 // pop value from stack to local variable 堆栈最顶上的值“27”出栈,
                         //并被赋给索引位置“0”处的局部变量 cube,即内存中变量 cube 的值为“27”。
    L_0007: ldloc.0  // 局部变量 cube 的值“27”入栈。
    L_0008: call void [mscorlib]System.Console::WriteLine(int32) 
                      // 控制台输出堆栈最顶上的32 位整数“27”。
    L_000d: nop // no operation.
    L_000e: ret  // return from method.
}

 使用ILGenerator的Emit方法,改写为:

                ILGenerator il = methodBuilder.GetILGenerator();

                var cube = il.DeclareLocal(typeof(int));
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Mul);
                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Mul);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }));
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ret);

 

---------------------------------------------------------------------------------------------------

例子 4 : 循环语句

public void SeparateString(string source)
        {
            if (source == null)
                return;
            int count = source.Length;
            char c;
            for (int i = 0; i < count; i++)
            {
                c = source[i];
                Console.WriteLine(c);
            }
        }

 生成的IL:

.method public hidebysig instance void SeparateString(string source) cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 count,
        [1] char c,
        [2] int32 i,
        [3] bool CS$4$0000)
                 // 索引为“3”的这个布尔型局部变量在 C# 代码中并未显式声明,是编译器编译时添加的,
                //用于保存执行过程中布尔运算的结果,比如比较 source 是否为空时,以及比较 i<count 时。
    L_0000: nop 
    L_0001: ldarg.1 // 方法参数 source 的值入栈。
    L_0002: ldnull   // “空引用”null入栈。
    L_0003: ceq     // compare equal 比较栈顶的 null 和第二项的 source 是否相等,并
                          // 把结果 0(false,source 不为空)或 1(true,source 为空)入栈。
    L_0005: ldc.i4.0  // 32 位整型数“0”入栈。
    L_0006: ceq  // 比较栈顶的“0”和堆栈的第二项,第二项可能是“0”,也可能
                        // 是“1”。比较的结果“1”或“0”入栈。
    L_0008: stloc.3  // 栈顶的“1”或“0”出栈,被保存到索引为“3”的局部变量中。
    L_0009: ldloc.3    // 执行后,栈顶为“1”(source 不为空)或“0”(source 为空)。   
    L_000a: brtrue.s L_000e  // branch on non-false or non-null 判断栈顶是否
                               // 为“1”,如果是,跳转到第“IL_000e”行;否则继续往下执行。
    L_000c: br.s L_0036    // unconditional branch 当栈顶为“0”时,才会
                               // 执行到这一行,这一行的执行结果是程序无条件
                              // 跳转到第“IL_0036”行。
    L_000e: ldarg.1 
    L_000f: callvirt instance int32 [mscorlib]System.String::get_Length()
                              // 对堆栈最顶上的字符串调用其获取长度的实例方法,长度值被入栈。
                             // “get_Length()”实际是字符串 Length 属性的“get”部分。
    L_0014: stloc.0   // 局部变量 count 被赋值为字符串长度。
    L_0015: ldc.i4.0 
    L_0016: stloc.2    // 局部变量 i 被赋值为 0。
    L_0017: br.s L_002e  // 无条件跳转到第“IL_002e”行。
    L_0019: nop    
    L_001a: ldarg.1 
    L_001b: ldloc.2 
    L_001c: callvirt instance char [mscorlib]System.String::get_Chars(int32)
                            // source 中索引为 i 处的 char 值入栈。
    L_0021: stloc.1 
    L_0022: ldloc.1 
    L_0023: call void [mscorlib]System.Console::WriteLine(char)  // char 值被输出到控制台
    L_0028: nop 
    L_0029: nop 
    L_002a: ldloc.2     // i 值入栈。
    L_002b: ldc.i4.1    // 32 位整数 1 入栈。
    L_002c: add    // i+1 的结果入栈。
    L_002d: stloc.2    // i=i+1。
    L_002e: ldloc.2  // i 值入栈。
    L_002f: ldloc.0  // count 值入栈。
    L_0030: clt      // compare less than 比较 i<count 是否为真,比较结果入栈。
    L_0032: stloc.3 
    L_0033: ldloc.3 
    L_0034: brtrue.s L_0019  // 如果 i<count 则跳转到第“IL_0019”行。
    L_0036: ret 
}

 
 

---------------------------------------------------------------------------------------------------

例子 5 : 基本类型

        public void SayHello(string toWhom)
        {
            int i = 1000;
            double d = 3.1;
            float f = 4.2F;
            
            Console.WriteLine(i);
            Console.WriteLine(d);
            Console.WriteLine(f);
        }

生成的IL:

.method public hidebysig newslot virtual final instance void SayHello(string toWhom) cil managed
{
    .maxstack 1
    .locals init (
        [0] int32 i,
        [1] float64 d,
        [2] float32 f)
    L_0000: nop
    L_0001: ldc.i4


  1000
    L_0002: stloc.0 
    L_0003: ldc.r8 3.1
    L_000c: stloc.1 
    L_000d: ldc.r4 4.2
    L_0012: stloc.2 
    L_0013: ldloc.0 
    L_0014: call void [mscorlib]System.Console::WriteLine(int32)
    L_0019: nop 
    L_001a: ldloc.1 
    L_001b: call void [mscorlib]System.Console::WriteLine(float64)
    L_0020: nop 
    L_0021: ldloc.2 
    L_0022: call void [mscorlib]System.Console::WriteLine(float32)
    L_0027: nop 
    L_0028: ret 
}

 
 

---------------------------------------------------------------------------------------------------

例子 5 : if语句

            int i = 1;
            if (i > 1)
            {
                Console.WriteLine("i > 1");
            }
            else if (i == 1)
            {
                Console.WriteLine("i == 1");
            }
            else
            {
                Console.WriteLine("i < 1");
            }

 生成的IL:

    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.1 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.1 
    L_0005: cgt 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_001d
    L_000e: nop 
    L_000f: ldstr "i > 1"
    L_0014: call void [mscorlib]System.Console::WriteLine(string)
    L_0019: nop 
    L_001a: nop 
    L_001b: br.s L_0044
    L_001d: ldloc.0 
    L_001e: ldc.i4.1 
    L_001f: ceq 
    L_0021: ldc.i4.0 
    L_0022: ceq 
    L_0024: stloc.1 
    L_0025: ldloc.1 
    L_0026: brtrue.s L_0037
    L_0028: nop 
    L_0029: ldstr "i == 1"
    L_002e: call void [mscorlib]System.Console::WriteLine(string)
    L_0033: nop 
    L_0034: nop 
    L_0035: br.s L_0044
    L_0037: nop 
    L_0038: ldstr "i < 1"
    L_003d: call void [mscorlib]System.Console::WriteLine(string)
    L_0042: nop 
    L_0043: nop 
    L_0044: ret 

 使用ILGenerator的Emit方法,改写为:

                MethodBuilder methodBuilder = typeBuilder.DefineMethod("If",
                             MethodAttributes.Public,
                             typeof(void),
                             null);
                ILGenerator il = methodBuilder.GetILGenerator();

                var i = il.DeclareLocal(typeof(int));
                var b = il.DeclareLocal(typeof(bool));
                var lblElse = il.DefineLabel();
                var lblElse2 = il.DefineLabel();
                var lblEnd = il.DefineLabel();

                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈
                il.Emit(OpCodes.Stloc, i); //取栈中第一个值,赋值局部变量i
                il.Emit(OpCodes.Ldloc, i); //局部变量i入栈
                il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈
                il.Emit(OpCodes.Cgt);      //取栈中前两个值,进行大于比较,
                            //如果第一个值大于第二个值,则将整数值 1 (int32) 入栈;反之,将 0 (int32)入栈。
                            //此时的值为 1
                il.Emit(OpCodes.Ldc_I4_0);  //取整数0,入栈
                il.Emit(OpCodes.Ceq);       //取栈中前两个值,进行等于比较,
                            //如果这两个值相等,则将整数值 1(int32)入栈;否则,将 0 (int32) 入栈
                            //此时的值为 0
                il.Emit(OpCodes.Stloc, b); //取栈中第一个值,赋值局部变量b
                il.Emit(OpCodes.Ldloc, b);  //局部变量b入栈
                il.Emit(OpCodes.Brtrue_S, lblElse); //如果为真,控制流转到lblElse标签处,如果为假,继续下一条语句
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldstr, "i > 1"); //引用字符串
                il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Br_S, lblEnd);
                il.MarkLabel(lblElse); //设定标签lblElse
                il.Emit(OpCodes.Ldloc, i); //局部变量i入栈
                il.Emit(OpCodes.Ldc_I4_1); //取整数1,入栈
                il.Emit(OpCodes.Ceq);       //取栈中前两个值,进行等于比较
                il.Emit(OpCodes.Ldc_I4_0);  //取整数0,入栈
                il.Emit(OpCodes.Ceq);       //取栈中前两个值,进行等于比较
                il.Emit(OpCodes.Stloc, b); //取栈中第一个值,赋值局部变量b
                il.Emit(OpCodes.Ldloc, b);  //局部变量b入栈
                il.Emit(OpCodes.Brtrue_S, lblElse2); //如果为真,控制流转到lblElse2标签处,如果为假,继续下一条语句
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldstr, "i == 1"); //引用字符串
                il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Br_S, lblEnd);
                il.MarkLabel(lblElse2); //设定标签lblElse2
                il.Emit(OpCodes.Nop);
                il.Emit(OpCodes.Ldstr, "i < 1"); //引用字符串
                il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //输出字符串
                il.Emit(OpCodes.Nop);
                il.MarkLabel(lblEnd); //设定标签lblEnd
                il.Emit(OpCodes.Ret);
 

 

 

 

 

---------------------------------------------------------------------------------------------------

测试完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

namespace ILDemo
{
    public class UserInfo
    {
        public void Test1()
        {
            Console.WriteLine("aaaa");
        }

        /*
         各种方法
        */
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            AssemblyName asmName = new AssemblyName();
            asmName.Name = "ILDemo";
            AssemblyBuilder asmBuilder = Thread.GetDomain().DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
            ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("MyTestDemo");
            TypeBuilder typeBuilder = modBuilder.DefineType(
                                    "UserInfo",
                                    TypeAttributes.Public,
                                    typeof(object),
                                    null);

            MethodBuilder methodBuilder = typeBuilder.DefineMethod("Test1",
                         MethodAttributes.Public,
                         typeof(void),
                         null);


            ILGenerator il = methodBuilder.GetILGenerator();

            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ldstr, "aaaa");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
            il.Emit(OpCodes.Nop);
            il.Emit(OpCodes.Ret);

            /*
             各种方法的Emit的实现
            */


            Type type = typeBuilder.CreateType();
            object userInfo = Activator.CreateInstance(type);
            MethodInfo _MethodInfo = type.GetMethod("Test1");
            _MethodInfo.Invoke(userInfo, null);

            Console.ReadKey();
        }
    }
}
 

 

 

分享到:
评论

相关推荐

    Emit学习之旅

    Emit学习之旅是一个深入探索C# Emit技术的教程,它为开发者提供了动态生成IL(Intermediate Language)代码的能力。Emit是.NET Framework的一部分,允许程序员在运行时构建和执行方法,这是实现元编程的重要工具。...

    VUE--组件示例 博客 https://gudianxiaoshuo.blog.csdn.net/article/detail

    在Vue.js框架中,组件是构建可复用代码的基本单元,是 Vue 应用的核心组成部分。Vue组件可以被视为自定义HTML元素,它们有自己的属性、事件和生命周期方法,能够封装任何复杂的逻辑,使得代码结构清晰、易于维护。...

    PyQt学习随笔:自定义信号连接时报AttributeError: ‘PyQt5.QtCore.pyqtSignal’ object has no attribute ‘connect’

    在PyQt编程中,信号和槽机制是核心概念之一,用于实现对象间的通信。当一个对象的状态发生改变时,它可以发出一个信号,其他对象可以通过连接这个信号来响应这个改变。在学习过程中,可能会遇到错误“AttributeError...

    Angular权威指南 英文名:Manning.Angular.in.Action 出书日期:2018.3 PDF高清带书签

    在这个例子中,`NavbarComponent`定义了一个名为`refreshEvent`的输出属性,并在按钮点击事件中触发该事件。父组件可以监听这个事件并执行相应的逻辑。 ##### 3. 服务(Services) 除了通过输入和输出进行组件间的...

    Emit 学习资源汇总

    Emit,全称为Event Emitter,是Node.js中的一个核心模块,它在JavaScript世界中扮演着事件驱动的重要角色。在本文中,我们将深入探讨Emit的相关知识点,包括其原理、用法以及在实际开发中的应用。 事件驱动是Node....

    vue 轮播图 带自动分页 _vue常用的轮播组件

    vnode.context.$emit('outside-click'); } }); }, unbind(el) { el.removeEventListener('click', () =&gt; {}); }, }, }, ``` 然后在父组件中监听这个事件,暂停自动切换: ```html ``` ```javascript ...

    用于简单的反射对象的属性,字段,方法的方式

    ILProperty文件中,第一个类 ILProperty 中void LdValue() 方法 50行:this.il.Emit(OpCodes.Ldnull); 改为一对大括号{} if (this.obj.GetGetMethod().IsStatic) this.il.Emit(OpCodes.Ldnull); else this.target....

    Use Node.js as a full cloud enviroment development stack

    Node.js的独特之处在于它完全拥抱JavaScript,不仅在服务器端代码中使用,还延伸至浏览器端,实现了真正的全栈JavaScript开发。此外,Node.js采用了基于异步I/O的并发模型,通过回调函数实现非阻塞操作,这使得Node....

    signal PYQT5

    emit@resource://devtools/shared/event-emitter.js:178:15 emit@resource://devtools/shared/event-emitter.js:255:5 setNodeFront@resource://devtools/client/framework/selection.js:153:5 onDetached@resource:...

    emit.js:JavaScript中的高效极简事件发射器

    emit.js JavaScript中的高效极简事件发射器。安装它可以与bower或npm一起使用: bower install emit.jsnpm install emit.js在HTML中包含emit.min.js ,并且在全局范围内现在可以使用emit对象: &lt; script type =" ...

    EMIT学习经典实例

    2. **Harold.Net.Emit.gpState** 这个文件可能是一个项目或库,其中包含关于如何使用EMIT来管理状态或执行特定任务的示例代码。gpState可能代表“通用程序状态”,它可能是用于演示如何动态生成处理状态变化的代码...

    使用yarn create umi安装Ant Design Pro时报错TypeError: self.env.emit is not a function

    解决self.env.emit is not a function报错 报错内容 TypeError: self.env.emit is not a function at /usr/local/share/.config/yarn/global/node_modules/yeoman-generator/lib/index.js:653:22 at ...

    支持engin.io的websocket

    socketIO.emit('your_event_name', {'data': 'hello world'}) ``` 5. **处理响应**:你可以注册回调函数来处理服务器发送的事件和数据。 ```python def on_message_received(*args): print('Received:', args...

    bootcamp-desafio02:Desafio:Conceitos做Node.js

    4. **文件系统(fs)模块**:学习使用Node.js内置的fs模块进行文件操作,如读取、写入、创建、删除、重命名文件和目录。 5. **HTTP服务器**:构建简单的HTTP服务器,掌握`http`或`http2`模块的用法,实现接收请求并...

    socket.io API文档

    在Node.js项目中使用Socket.IO,首先需要安装它。安装命令如下: ```bash npm install socket.io ``` #### 三、使用Node.js HTTP服务器 ##### 1. 服务器端设置 ```javascript // 导入必要的模块 var app = require...

    carNumber.zip

    在微信小程序开发中,创建一个车牌号输入组件(虚拟键盘)是一项常见的需求,尤其是在交通、停车或汽车服务类的应用中。"carNumber.zip" 文件提供了一个实现这一功能的示例,帮助开发者创建一个用户友好且定制化的...

    Vue第四天.xmind

    自定义事件:子组件可以通过 $emit 触发事件,父组件可以监听这些事件来执行操作。  3.Vuex:对于大型应用,Vuex 是一个状态管理模式和库,用于集中管理所有组件的公共状态。  4.插槽:Vue 允许你将父组件模板中的...

    博客:https:daviddriscoll.me

    组件可以拥有自己的状态、方法和生命周期,也可以接收外部输入(props)和向父组件发出事件(emit)。在博客中可能涵盖如何创建、使用及优化组件的技巧。 3. **Vuex状态管理**:对于大型项目,Vuex是Vue官方推荐的...

    Vue学习之旅之重点1:组件与数据传递

    在Vue.js的学习旅程中,组件化开发是其核心特性之一,极大地提高了代码的复用性和组织性。本篇文章将深入探讨Vue中的组件以及如何在组件间进行数据传递,旨在帮助初学者理解并掌握这一关键概念。 一、Vue组件 Vue...

    Qt界面间互相通信.rar

    总的来说,"Qt界面间互相通信.rar" 文件提供的示例是一个很好的学习资源,可以帮助开发者理解如何在Qt环境中实现窗口间通信,从而创建更加动态和交互性强的用户界面。通过熟练掌握这一技巧,你可以构建更复杂的应用...

Global site tag (gtag.js) - Google Analytics