MSIL实用指南-Action的生成和调用

MSIL实用指南-Action的生成和调用

System.Action用于封装一个没有参数没有返回值的方法。这里生成需要Ldftn指令。

下面讲解怎生成如下的程序。

class ActionTest
    {
        public static void RunAction(Action act)
        {
            act();
        }

        public static void TestRunAction()
        {
            Action act = () => { Console.WriteLine("Test Action"); };
            RunAction(act);
        }
    }

 

一.Action的调用
Action有方法Invoke,只要加载对象,调用Invoke方法就可以了。
实例代码:

ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Callvirt, typeof(Action).GetMethod("Invoke", new Type[] { }));

 

二、生成Lamda表示式
这里的Lamda表示式即一个匿名方法,它只有一条语句。
所以这样生成:

lambdaMethod = typeBuilder.DefineMethod("<LambdaMethod>",
MethodAttributes.Private| MethodAttributes.Static,
typeof(void), new Type[] { });
ILGenerator ilGenerator = lambdaMethod.GetILGenerator();
ilGenerator.EmitWriteLine("Test Action");
ilGenerator.Emit(OpCodes.Ret);

 

三、生成Action实例
Action是委托,它需要使用Ldftn和Newobj指令生成实例
实例代码

ilGenerator.Emit(OpCodes.Ldnull);//静态方法加载null,实例方法加载arg_0
ilGenerator.Emit(OpCodes.Ldftn, lambdaMethod);
ilGenerator.Emit(OpCodes.Newobj, typeof(Action).GetConstructors()[0]);

 

完整程序:

 

using System;
using System.Reflection;
using System.Reflection.Emit;

namespace LX1_ILDemo
{
    class Demo28_Action
    {
        static string binaryName = "Demo28_Action.exe";
        static string namespaceName = "LX1_ILDemo";
        static string typeName = "Demo28";

        static AssemblyBuilder assemblyBuilder;
        static ModuleBuilder moduleBuilder;
        static TypeBuilder typeBuilder;
        static MethodBuilder mainMethod;
        static MethodBuilder runActionMethod;
        static MethodBuilder lambdaMethod;

        static void Emit_TestMethod()
        {
            runActionMethod = typeBuilder.DefineMethod("RunAction", MethodAttributes.Public
               | MethodAttributes.Static, typeof(void), new Type[] { typeof(Action) });
            ILGenerator ilGenerator = runActionMethod.GetILGenerator();
            ilGenerator.Emit(OpCodes.Ldarg_0);
            ilGenerator.Emit(OpCodes.Callvirt, typeof(Action).GetMethod("Invoke", new Type[] { }));
            ilGenerator.Emit(OpCodes.Ret);
        }

        public static void Generate()
        {
            InitAssembly();
            typeBuilder = moduleBuilder.DefineType(namespaceName + "." + typeName, TypeAttributes.Public);

            Emit_TestMethod();
            GenerateMain();

            assemblyBuilder.SetEntryPoint(mainMethod, PEFileKinds.ConsoleApplication);
            SaveAssembly();
            Console.WriteLine("生成成功");
        }

        static void GenerateLambda()
        {
            lambdaMethod = typeBuilder.DefineMethod("<LambdaMethod>",
                MethodAttributes.Private| MethodAttributes.Static,
                typeof(void), new Type[] { });
            ILGenerator ilGenerator = lambdaMethod.GetILGenerator();
            ilGenerator.EmitWriteLine("Test Action");
            ilGenerator.Emit(OpCodes.Ret);
        }

        static void GenerateMain()
        {
            mainMethod = typeBuilder.DefineMethod("Main", MethodAttributes.Public
                | MethodAttributes.Static, typeof(void), new Type[] { });
            ILGenerator ilGenerator = mainMethod.GetILGenerator();

            LocalBuilder localBuilderv1 = ilGenerator.DeclareLocal(typeof(Action));

            GenerateLambda();
            ilGenerator.Emit(OpCodes.Ldnull);//静态方法加载null,实例方法加载arg_0
            ilGenerator.Emit(OpCodes.Ldftn, lambdaMethod);
            ilGenerator.Emit(OpCodes.Newobj, typeof(Action).GetConstructors()[0]);
            ilGenerator.Emit(OpCodes.Stloc_0);

            ilGenerator.Emit(OpCodes.Ldloc_0);
            ilGenerator.Emit(OpCodes.Call, runActionMethod);

            EmitReadKey(ilGenerator);

            ilGenerator.Emit(OpCodes.Ret);
        }

        static void EmitReadKey(ILGenerator ilGenerator)
        {
            MethodInfo readKeyMethod = typeof(Console).GetMethod("ReadKey", new Type[] { });
            ilGenerator.Emit(OpCodes.Call, readKeyMethod);
            ilGenerator.Emit(OpCodes.Pop);
        }

        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

 

posted @ 2018-04-17 14:12  Z语言  阅读(290)  评论(0编辑  收藏  举报