反射允许我们在运行时获取对象的相关信息,创建对象的实例,执行方法。Emit是作为反射的一个比较高级的功能。使用Emit,可以从零开始动态的创建程序集及类。提供程序的灵活性。本文主要介绍.NET Core中Emit的使用。
程序集构成了 .NET 应用程序的部署、版本控制、重用、激活范围和安全权限的基本单元。 程序集是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。 程序集采用可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式,是 .NET 应用程序的构建基块 。 它们向公共语言运行时提供了注意类型实现代码所需的信息。在 .NET 和 .NET Framework 中,可从一个或多个源代码文件生成程序集。 在 .NET Framework 中,程序集可以包含一个或多个模块。使用System.Reflection.Emit可以动态创建程序集。
模块是程序集内代码的逻辑集合,每个模块可以使用不同的语言编写,大多数情况下,一个程序集包含一个模块。程序集包括了代码、版本信息、元数据等。模块是没有 Assembly 清单的 Microsoft 中间语言(MSIL)文件。
Emit可以使用MSIL指令动态编写程序逻辑,然后将指令编译成程序集。通过编写代码的方式动态创建程序。比如软件授权,可以输入授权信息后,生成一个授权的DLL,使用Emit实现动态AOP框架等。
1).NET Framework中使用Emit
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Text;
- using System.Threading.Tasks;
- namespace ConsoleApp1
- {
- class Program
- {
- static void Main(string[] args)
- {
- CreateAssembly();
- LoadAssembly();
- Console.ReadKey();
- }
- public static void LoadAssembly()
- {
- var ass = AppDomain.CurrentDomain.Load("MyAssembly");
- var m = ass.GetModule("MyModule");
- var ts = m.GetTypes();
- var t = ts.FirstOrDefault();
- if (t != null)
- {
- object obj = Activator.CreateInstance(t);
- var me = t.GetMethod("MyMethod");
- me.Invoke(obj, null);
- }
- }
- public static void CreateAssembly()
- {
- //定义一个程序集的名称
- var asmName = new AssemblyName("MyAssembly");
- //首先就需要定义一个程序集
- var defAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
- //定义一个构建类
- var defModuleBuilder = defAssembly.DefineDynamicModule("MyModule", "MyAssembly.dll");
- //定义一个类
- var defClassBuilder = defModuleBuilder.DefineType("MyClass", TypeAttributes.Public);
- //定义一个方法
- var defMethodBuilder = defClassBuilder.DefineMethod("MyMethod",
- MethodAttributes.Public,
- null,//返回类型
- null//参数类型
- );
- //获取IL生成器
- var il = defMethodBuilder.GetILGenerator();
- //定义一个字符串
- il.Emit(OpCodes.Ldstr, "生成的第一个程序");
- //调用一个函数
- il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
- //返回到方法开始(返回)
- il.Emit(OpCodes.Ret);
- //创建类型
- defClassBuilder.CreateType();
- //保存程序集
- defAssembly.Save("MyAssembly.dll");
- }
- }
- }
2).NET Core中使用Emit
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- namespace ConsoleApp2
- {
- class Program
- {
- public static void Main()
- {
- AssemblyName aName = new AssemblyName("ChefDynamicAssembly");
- AssemblyBuilder ab =
- AssemblyBuilder.DefineDynamicAssembly(
- aName,
- AssemblyBuilderAccess.Run);
- ModuleBuilder mb = ab.DefineDynamicModule(aName.Name + ".dll");
- TypeBuilder tb = mb.DefineType("Commander");
- var attrs = MethodAttributes.Public;
- // 使用类型构建器创建一个方法构建器
- MethodBuilder methodBuilder = tb.DefineMethod("Do", attrs, typeof(string), Type.EmptyTypes);
- // 通过方法构建器获取一个MSIL生成器
- var IL = methodBuilder.GetILGenerator();
- // 开始编写方法的执行逻辑
- // var store = new string[3];
- var store = IL.DeclareLocal(typeof(string[]));
- IL.Emit(OpCodes.Ldc_I4, 3);
- IL.Emit(OpCodes.Newarr, typeof(string));
- IL.Emit(OpCodes.Stloc, store);
- //store[0] = "C"
- IL.Emit(OpCodes.Ldloc, store);
- IL.Emit(OpCodes.Ldc_I4, 0);
- IL.Emit(OpCodes.Ldstr, "C");
- IL.Emit(OpCodes.Stelem, typeof(string));
- //store[1] = "JAVA"
- IL.Emit(OpCodes.Ldloc, store);
- IL.Emit(OpCodes.Ldc_I4, 1);
- IL.Emit(OpCodes.Ldstr, "JAVA");
- IL.Emit(OpCodes.Stelem, typeof(string));
- //store[2] = "Python"
- IL.Emit(OpCodes.Ldloc, store);
- IL.Emit(OpCodes.Ldc_I4, 2);
- IL.Emit(OpCodes.Ldstr, "Python");
- IL.Emit(OpCodes.Stelem, typeof(string));
- // IChef chef = new GoodChef();
- var chef = IL.DeclareLocal(typeof(IChef));
- IL.Emit(OpCodes.Newobj, typeof(StoreChef).GetConstructor(Type.EmptyTypes));
- IL.Emit(OpCodes.Stloc, chef);
- //var dish = chef.Cook(vegetables);
- var dish = IL.DeclareLocal(typeof(string));
- IL.Emit(OpCodes.Ldloc, chef);
- IL.Emit(OpCodes.Ldloc, store);
- IL.Emit(OpCodes.Callvirt, typeof(IChef).GetMethod("Cook"));
- IL.Emit(OpCodes.Stloc, dish);
- // return dish;
- IL.Emit(OpCodes.Ldloc, dish);
- IL.Emit(OpCodes.Ret);
- //方法结束
- // 从类型构建器中创建出类型
- var dynamicType = tb.CreateType();
- // 通过反射创建出动态类型的实例
- var commander = Activator.CreateInstance(dynamicType);
- Console.WriteLine(dynamicType.GetMethod("Do").Invoke(commander, null).ToString());
- Console.ReadLine();
- }
- }
- public interface IChef
- {
- string Cook(string[] store);
- }
- public class StoreChef : IChef
- {
- public string Cook(string[] store)
- {
- return "Value:" + string.Join("+", store);
- }
- }
- }