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 @   Z语言  阅读(292)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示