.NET中的Emit,其实是个很强大的东东,它允许你在你的程序运行时,动态的生成代码。看到这里,也许大家会联想到Reflection,的确,Reflection也是我们平时用得比较多的一种技术,通过Reflection,我们能通过程序集中的元数据,动态的生成目标程序集的Instance,并执行它。而Emit的功能,恰恰和Reflection遥相呼应,前者允许我们动态的生成代码,后者允许我们动态的“查看”和运行代码。Emit和Reflection合在一起,简直就是双剑合璧,简直就是幸福的一家……难怪,微软也很邪恶的把Emit放在了System.Reflection.Emit。
其实哥平时的开发中,用得比较多的,还是Reflection(反射)了,不过早已久仰Emit的大名,又没闲暇时间来窥探一把,最近总算比较闲了,决心研究研究强大的Emit。
话不多说,代码是最有力的说明,先献上一个通过Emit动态创建并生成程序集的例子:
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace Emit_Learn
{
class Program
{
static void Main(string[] args)
{
var name = new AssemblyName("HelloEmit");
var assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(name,
AssemblyBuilderAccess.RunAndSave); //创建程序集
var modelBuilder = assemblyBuilder.DefineDynamicModule("HelloEmit", "HelloEmit.dll"); //创建模块
var typeBuilder = modelBuilder.DefineType("HelloEmit"); //定义类型
var methodBuilder = typeBuilder.DefineMethod("Execute", MethodAttributes.Public, null, null); //创建MethodBuilder
var il = methodBuilder.GetILGenerator(); //获取ILGenerator,用于生成方法的IL
il.Emit(OpCodes.Ldstr, "Hello, Emit");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Ret);
typeBuilder.CreateType();
assemblyBuilder.Save("HelloEmit.dll"); //保存动态生成的程序集到磁盘文件
}
}
}
在IDE中输入以上代码,F5运行,你会发现,在你的程序的Debug目录,会生成一个HelloEmit.dll。没错,这就是我们的程序动态生成的程序集,并且它是可执行的。以上的代码,动态生成的程序集,包含一个叫HelloEmit的类,类中有一个public属性的Execute方法。方法中调用Console输出字符串:Hello,Emit
这个类,等价于如下的C#代码:
internal class HelloEmit
{
// Methods
public void Execute()
{
Console.WriteLine("Hello, Emit");
}
}
我们也可以使用.NET Reflector一类的工具,打开生成的Dll查看,顺便验证一下。
Emit适用的场景:适用于对业务灵活性要求很高的系统,可以在运行时动态更改业务逻辑,并动态生成代码。