`

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();
        }
    }
}
 

 

 

分享到:
评论

相关推荐

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

    如果使用自定义信号,一定要记得信号是类变量,必须在类中定义,不能在实例方法中定义,否则后面发射信号和连接槽方法时都会报错。 案例: class configWin(ui_configWin.Ui_configWin,QtWidgets.QWidget): def __...

    Emit学习之旅

    学习Emit的简要教程,非常不错的说明!

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

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

    Emit 学习资源汇总

    Emit 学习资源汇总 Emit 学习资源汇总

    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 =" ...

    使用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 ...

    $emit触发事件拿不到传递的参数.zip

    $emit触发事件拿不到传递的参数 https://blog.csdn.net/qq_36413371/article/details/102795742

    EMIT学习经典实例

    EMIT学习经典实例 EMIT学习经典实例 非常不错的一个实例

    大事记

    大事记事件提供了一种简单的观察者模式,用于订阅和侦听Vapor应用程序中的事件。 这个想法是基于。注册事件和侦听器// Eventstruct ThingHappened : Event { ... }// Listenersstruct NofifyThing : Listener { ... ...

    前端语言vue常见面试题

    简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习; 双向数据绑定:保留了angular的特点,在数据操作方面更为简单; 组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着...

    Managed.Reflection, System.Reflection [.Emit ]的托管替换.zip

    Managed.Reflection, System.Reflection [.Emit ]的托管替换 Managed.ReflectionManaged.Reflection 是对 System.Reflection 和 System.Reflection.Emit的完全管理的替换。 System.Reflection 不同,它不绑定到

    10.(vue3.x+vite)组件间通信方式之props与$emit.rar

    前端技术社区总目录有各种各样的前端示例其地址为: https://blog.csdn.net/m0_60387551/article/details/128017725

    VueJS_learn-vue-js-master:Infron - Vue.js 入门

    学习vue-js 讲座名称:【Infron】Vue.js入门-Vue.js时代指导老师:板桥船长技能:前端、javascript、Vue.js、Web 开发 什么是Vue? 与 MVVM 模式的 ViewModel 层对应的视图级库。 如何在相同的组件级别之间进行...

    解决Vue.js父组件$on无法监听子组件$emit触发事件的问题

    最近学习vuejs看例子中用$on无法监听子组件$emit触发事件: 使用版本 vue.js 2.2.5 参考文献 1.vuejs API 2.解决实例 问题分析 1.之前写的自定义组件事件触发为this.$emit(“myclick”,this.todo.text);,这样this...

    gremit:.NET Reflection.Emit扩展

    GrEmit是一个包含不同助手的库,用于使用Reflection.Emit生成代码,主要的是GroboIL- 的智能包装器。 用法 GroboIL替代了ILGenerator。 除了调用ILGenerator.Emit(OpCode,..),还可以调用GroboIL.OpCode(..)。...

    vue子传父关于.sync与$emit的实现

    $emit(update: prop, “newPropVulue”) 这个模式,使子组件向父组件传达:更新属性,并抛出新的属性值 .sync 修饰符 是父组件中修改prop值得修饰符 一:什么地方需要用到.sync修饰符呢 当子传父,父级有两数据,而...

    Emit实现AOP示例

    纯手工打造Emit实现AOP private static void OverrideMethods(TypeBuilder tb, MethodInfo method) { if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return; Type[] paramTypes = ...

    dva-socket.io:dva的socket.io插件

    use ( createSocket ( 'http://127.0.0.1:8080' , null , { // when server push an server-message event, // it will dispatch an action use server data, on : [ 'server-message' ] , emit : [ // when you ...

    Socket.IOiOS客户端.zip

    Socket.IO 的开源 iOS 客户端,使用 swift 编写。... let socket = SocketIOClient(socketURL: "localhost:8880") ... socket.emit("response", "Hello!") } socket.connect() 标签:Socket

Global site tag (gtag.js) - Google Analytics