zoukankan      html  css  js  c++  java
  • MSIL实用指南-加载和保存参数


    本篇讲解怎么加载和保存参数,以及参数起始序号的确定。


    参数的加载
    加载参数的指令是Ldarg、Ldarg_S、Ldarg_0、Ldarg_1、Ldarg_2、Ldarg_3。
    Ldarg_0是加载第0个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_0);
    Ldarg_1是加载第1个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_1);
    Ldarg_2是加载第2个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_2);
    Ldarg_3是加载第3个参数,例子 ilGenerator.Emit(OpCodes.Ldarg_3);
    Ldarg_S是加载次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Ldarg_S,5);
    Ldarg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Ldarg,6)。

    我们可以根据指令的说明实现一个方便调用的方法,源码如下

            public static void LoadArg(ILGenerator ilGenerator, int argIndex)
            {
                switch (argIndex)
                {
                    case 0:
                        ilGenerator.Emit(OpCodes.Ldarg_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Ldarg_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Ldarg_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Ldarg_3);
                        return;
                }
                if (argIndex > 0 && argIndex <= 255)
                {
                    ilGenerator.Emit(OpCodes.Ldarg_S, argIndex);
                    return;
                }
                else
                {
                    ilGenerator.Emit(OpCodes.Ldarg, argIndex);
                    return;
                }
            }

    参数的保存
    保存参数的指令是Starg、Starg_S
    Ldarg_S是保存次序为0到255的参数,例子 ilGenerator.Emit(OpCodes.Starg_S,1);
    Starg加载任意次序的参数,例子 ilGenerator.Emit(OpCodes.Starg,6)。

    我们可以根据指令的说明实现一个方便调用的方法,源码如下

            public static void StormArg(ILGenerator ilGenerator, int argIndex)
            {
                if (argIndex > 0 && argIndex <= 255)
                {
                    ilGenerator.Emit(OpCodes.Starg_S, argIndex);
                    return;
                }
                else
                {
                    ilGenerator.Emit(OpCodes.Starg, argIndex);
                    return;
                }
            }
    

      

    参数起始序号的确定
    参数的起始序号不一定从0开始,也可能从1开始,这是由方法是否是static决定的。
    如果参数所在的方法是static修饰的,序号从0开始;
    如果不是static修饰,则从0开始。

    完整的一个例子如下

    using System;
    using System.Reflection;
    using System.Reflection.Emit;
    
    namespace LX1_ILDemo
    {
        class Demo08_Arg
        {
            static string binaryName = "Demo08_Arg.exe";
            static string namespaceName = "LX1_ILDemo";
            static string typeName = "ArgTest";
    
            static AssemblyBuilder assemblyBuilder;
            static ModuleBuilder moduleBuilder;
            static TypeBuilder typeBuilder;
            static MethodBuilder mainMethod;
            static MethodBuilder printStaticMethod;
            static MethodBuilder printInstaceMethod;
            static ConstructorBuilder constructorBuilder;
    
            static void Emit_PrintInstace()
            {
                printInstaceMethod = typeBuilder.DefineMethod("PrintInstanceArg", MethodAttributes.Public,
                   typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) });
                ILGenerator printILInstaceGenerator = printInstaceMethod.GetILGenerator();
                ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1");
                ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2");
                ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3");
                ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4");
                ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5");
    
                MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
                MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
                LoadArg(printILInstaceGenerator,1);
                printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                LoadArg(printILInstaceGenerator, 2);
                printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                LoadArg(printILInstaceGenerator, 3);
                printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                LoadArg(printILInstaceGenerator, 4);
                printILInstaceGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                LoadArg(printILInstaceGenerator, 5);
                printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                printILInstaceGenerator.Emit(OpCodes.Ldstr, "world");
                StormArg(printILInstaceGenerator, 5);
                LoadArg(printILInstaceGenerator, 5);
                printILInstaceGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                printILInstaceGenerator.Emit(OpCodes.Ret);
            }
    
            public static void LoadArg(ILGenerator ilGenerator, int argIndex)
            {
                switch (argIndex)
                {
                    case 0:
                        ilGenerator.Emit(OpCodes.Ldarg_0);
                        return;
                    case 1:
                        ilGenerator.Emit(OpCodes.Ldarg_1);
                        return;
                    case 2:
                        ilGenerator.Emit(OpCodes.Ldarg_2);
                        return;
                    case 3:
                        ilGenerator.Emit(OpCodes.Ldarg_3);
                        return;
                }
                if (argIndex > 0 && argIndex <= 255)
                {
                    ilGenerator.Emit(OpCodes.Ldarg_S, argIndex);
                    return;
                }
                else
                {
                    ilGenerator.Emit(OpCodes.Ldarg, argIndex);
                    return;
                }
            }
    
            public static void StormArg(ILGenerator ilGenerator, int argIndex)
            {
                if (argIndex > 0 && argIndex <= 255)
                {
                    ilGenerator.Emit(OpCodes.Starg_S, argIndex);
                    return;
                }
                else
                {
                    ilGenerator.Emit(OpCodes.Starg, argIndex);
                    return;
                }
            }
    
            static void Emit_PrintStatic()
            {
                printStaticMethod = typeBuilder.DefineMethod("PrintStaticArg", MethodAttributes.Public
                   | MethodAttributes.Static, typeof(void), new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(string) });
                ILGenerator printILGenerator = printStaticMethod.GetILGenerator();
                ParameterBuilder ab1 = printStaticMethod.DefineParameter(1, ParameterAttributes.None, "i1");
                ParameterBuilder ab2 = printStaticMethod.DefineParameter(2, ParameterAttributes.None, "i2");
                ParameterBuilder ab3 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i3");
                ParameterBuilder ab4 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "i4");
                ParameterBuilder ab5 = printStaticMethod.DefineParameter(3, ParameterAttributes.None, "s5");
    
                MethodInfo writeIntLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) });
                MethodInfo writeStringLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
                printILGenerator.Emit(OpCodes.Ldarg_0);
                printILGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                printILGenerator.Emit(OpCodes.Ldarg_1);
                printILGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                printILGenerator.Emit(OpCodes.Ldarg_2);
                printILGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                printILGenerator.Emit(OpCodes.Ldarg_3);
                printILGenerator.Emit(OpCodes.Call, writeIntLineMethod);
                printILGenerator.Emit(OpCodes.Ldarg_S,4);
                printILGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                printILGenerator.Emit(OpCodes.Ldstr, "world");
                printILGenerator.Emit(OpCodes.Starg_S, 4);
                printILGenerator.Emit(OpCodes.Ldarg_S, 4);
                printILGenerator.Emit(OpCodes.Call, writeStringLineMethod);
                printILGenerator.Emit(OpCodes.Ret);
            }
    
            public static void Generate()
            {
                InitAssembly();
                typeBuilder = moduleBuilder.DefineType( namespaceName+"."+ typeName, TypeAttributes.Public);
                constructorBuilder = typeBuilder.DefineDefaultConstructor( MethodAttributes.Public);
                Emit_PrintStatic();
                Emit_PrintInstace();
                EmitMain();
    
                /*  设置assembly入口方法 */
                assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
                SaveAssembly();
                Console.WriteLine("生成成功");
            }
    
            static void EmitMain()
            {
                mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public 
                    | MethodAttributes.Static, typeof(void), new Type[] { });
                ILGenerator mainILGenerator = mainMethod.GetILGenerator();
    
                mainILGenerator.Emit(OpCodes.Ldc_I4,(int)200);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500);
                mainILGenerator.Emit(OpCodes.Ldstr,"hello static");
                mainILGenerator.Emit(OpCodes.Call, printStaticMethod);
    
                LocalBuilder localBuilder = mainILGenerator.DeclareLocal(typeof(string));
                mainILGenerator.Emit(OpCodes.Newobj, constructorBuilder);
                mainILGenerator.Emit(OpCodes.Stloc_0);
                mainILGenerator.Emit(OpCodes.Ldloc_0);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)200);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)300);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)400);
                mainILGenerator.Emit(OpCodes.Ldc_I4, (int)500);
                mainILGenerator.Emit(OpCodes.Ldstr, "hello instance");
                mainILGenerator.Emit(OpCodes.Call, printInstaceMethod);
    
                MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
                mainILGenerator.Emit(OpCodes.Call, readKeyMethod);
                mainILGenerator.Emit(OpCodes.Pop);
                mainILGenerator.Emit(OpCodes.Ret);
    
            }
    
            static void InitAssembly()
            {
                AssemblyName assemblyName = new AssemblyName(namespaceName);
                assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
                moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, binaryName);
            }
    
            static void SaveAssembly()
            {
                Type t = typeBuilder.CreateType(); //完成Type,这是必须的
                assemblyBuilder.Save(binaryName);
            }
        }
    }
    View Code
  • 相关阅读:
    ssm复习资料
    嵌入式开发实践的第二种柱状图代码
    嵌入式开发实践的简单登录代码
    嵌入式开发实践的柱状图代码
    学习ps的坑
    js的执行上下文
    js的渲染
    vue 使用Ueditor富文本的配置
    使用iview Upload进行多文件上传,编辑页初始已上传的图片失败的问题
    beforeEach钩子,next('/login') 跳转问题,无线循环导致Maximum call stack size exceeded问题
  • 原文地址:https://www.cnblogs.com/tkt2016/p/8623869.html
Copyright © 2011-2022 走看看