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
原文地址:https://www.cnblogs.com/tkt2016/p/8623869.html