一、反射发出(Emit)
.Net允许编译器或工具在运行时发出元数据和 Microsoft 中间语言 (MSIL),并在磁盘上生成可移植可执行 (PE) 文件(可选)。相关的API在System.Reflection.Emit命名空间下。
反射发出具有一下功能:
1.在运行时定义轻量全局方法(使用 DynamicMethod 类)并通过委托执行这些方法。
2.在运行时定义程序集,然后运行程序集以及/或者将程序集保存到磁盘。
3.在运行时定义程序集,运行程序集,然后卸载程序集并允许垃圾回收回收其资源。
4.在运行时在新的程序集中定义模块,然后运行模块以及/或者将模块保存到磁盘。
5.在运行时在模块中定义类型,创建这些类型的实例并调用其方法。
6.为已定义模块定义可供工具(如调试器和代码探查器)使用的符号化信息。
二、定义和执行动态方法
1.创建动态方法 方法名为SquareIt,返回值类型为long,参数列表为int
DynamicMethod squareIt = new DynamicMethod("SquareIt", typeof(long), new Type[] { typeof(int) }, typeof(Program).Module);
2.生成IL代码,将参数 int 加载到堆栈,将其转换为 long,复制 long,然后将这两个数字相乘
// 生成IL代码,将参数(int)加载到堆栈 ILGenerator il = squareIt.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // 将参数(int)加载到堆栈 il.Emit(OpCodes.Conv_I8); // 将int转换为long il.Emit(OpCodes.Dup);// 复制堆栈顶部的值 il.Emit(OpCodes.Mul);// 堆栈上最上面的两个值相乘 il.Emit(OpCodes.Ret);// 返回
3.通过调用 CreateDelegate 方法创建表示动态方法的委托,并执行此方法,并打印输出
// 将生成的动态方转换成委托类型 Func<int, long> invokeSquareIt = (Func<int, long>)squareIt.CreateDelegate(typeof(Func<int, long>)); // 执行动态方法 Console.WriteLine("9的平方 = {0}", invokeSquareIt(9));
4.打印结果
5.完整的代码
static void Main(string[] args) { // 创建动态方法 方法名为SquareIt,返回值类型为long,参数列表为int, DynamicMethod squareIt = new DynamicMethod("SquareIt", typeof(long), new Type[] { typeof(int) }, typeof(Program).Module); // 生成IL代码,将参数(int)加载到堆栈 ILGenerator il = squareIt.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); // 将参数(int)加载到堆栈 il.Emit(OpCodes.Conv_I8); // 将int转换为long il.Emit(OpCodes.Dup);// 复制堆栈顶部的值 il.Emit(OpCodes.Mul);// 堆栈上最上面的两个值相乘 il.Emit(OpCodes.Ret);// 返回 // 将生成的动态方转换成委托类型 Func<int, long> invokeSquareIt = (Func<int, long>)squareIt.CreateDelegate(typeof(Func<int, long>)); // 执行动态方法 Console.WriteLine("9的平方 = {0}", invokeSquareIt(9)); }
三、用Emit编写HelloWorld控制台
DynamicMethod method = new DynamicMethod("Main", null, Type.EmptyTypes); //生成IL代码 var il = method.GetILGenerator(); il.Emit(OpCodes.Ldstr, "Hello World!"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Ret); //创建委托 Action helloWorldMethod =(Action) method.CreateDelegate(typeof(Action)); helloWorldMethod.Invoke();