一、反射發出(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();