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

时间:2023-06-06 22:18:37

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()[]);

完整程序:

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()[]);
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);
}
}
}