在我们之前的文章,反射的第一部分:发现和执行里,我们已经介绍了System.Reflection命名空间及其包含的类,开发人员使用这些类可以查看程序集的元数据,并且可以在运行时查找和发现类型,甚至可以调用发现的代码。在这篇文章中,我们将探讨反射的高级功能:Emit,它具有在运行时动态的产生代码的功效。
回顾反射
首先,让我们快速的回顾一下,什么是反射以及反射可以被用来做什么。从第一部分内容中,你已经知道,反射是在运行时发现对象的相关信息,并且执行这些对象(创建对象实例,执行对象上的方法)。这个功能是由.NET的System.Reflection命名空间的类所提供的。这些被用于类型发现和动态调用的类包括:Assembly,Module,ConstructorInfo,MethodInfo以及其它。简单的说,它们不仅允许你浏览一个程序集暴露的类、方法、属性和字段,而且还允许你创建一个类型的实例以及执行这些类型上的方法(调用成员)。这些特性对于在运行时对象发现,已经很了不起了,但.NET的反射机制并没有到此结束。反射还允许你在运行时构建一个程序集,并且可以创建全新的类型。这就是反射发出(reflection emit)。
何谓反射发出(Reflection Emit)
System..Reflection.Emit命名空间嵌套在System.Reflection的下面,它是,允许你从零开始,动态的构建程序集和类型的所有框架类的根。在需要时动态的产生代码,类似这样的操作,虽然很少的开发人员会需要,但这对于.NET框架是一种凭据,证明有这样的工具可以解决有这样需求的业务问题。
注意:反射发出(reflection emit)并不能产生源代码。换句话说,你在这里的努力并不能创建VB.Net或者C#代码。相反,反射发出(reflection emit)类会创建MSIL op代码。
作为例子,使用反射发出(reflection emit)可能会是这样子的:
1. 创建一个新的程序集(程序集是动态的存在于内存中或把它们持久化到磁盘上)。
2. 在程序集内部,创建一个模块(module)。
3. 在模块内部,创建一个类型。
确切得说,当你使用Reflection.Emit类产生代码时,以上描述的是你实际中要遵循的过程。
依照上面列出的步骤,让我们探讨一下构建一个程序集,必要的操作。为此,我们举个非常简单的例子。假设你想构建一个类MathOps,它有一个公共的方法(函数),这个方法接收两个Integer类型的参数,然后返回它们的相加后的值。
第一步:构建程序集
稍微扩充一下上面列出的步骤,在实际的操作中,第一步更像是如下所述:
a) 创建一个AssemblyName(用于唯一标识和命名程序集)。
b) 获取当前应用程序域的一个引用(使用应用程序域提供的方法,返回AssemblyBuilder对象)。
c) 通过调用AppDomain.DefineDynamicAssembly产生一个AssemblyBuilder对象实例。
为了开始程序集的构建过程,你首先需要创建一个AssemblyName实例,用于标识你的程序集。如下:
name.Name = "MyAssembly";