1、程序集(Assembly)
程序集构成了 .NET 应用程序的部署、版本控制、重用、激活范围和安全权限的基本单元。 程序集是为协同工作而生成的类型和资源的集合,这些类型和资源构成了一个逻辑功能单元。 程序集采用可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式,是 .NET 应用程序的构建基块 。 它们向公共语言运行时提供了注意类型实现代码所需的信息。在 .NET 和 .NET Framework 中,可从一个或多个源代码文件生成程序集。 在 .NET Framework 中,程序集可以包含一个或多个模块。使用System.Reflection.Emit可以动态创建程序集。
2、模块(Module)
模块是程序集内代码的逻辑集合,每个模块可以使用不同的语言编写,大多数情况下,一个程序集包含一个模块。程序集包括了代码、版本信息、元数据等。模块是没有 Assembly 清单的 Microsoft 中间语言(MSIL)文件。
3、Emit的使用
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); } } }