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