在程序中,当我们需要动态的去加载程序集的时候(将对程序集的引用由编译时推移到运行时),反射是一种很好的选择。反射为.NET类型提供了高度的动态能力,包括:元数据的动态查询、绑定与执行、动态代码生成。常用的反射类型包含在System.Reflection和System.Reflection.Emit,反射包括程序集反射、类型反射、接口反射、类型成员反射。
编译时加载程序集
下面先从一个简单的例子说起,假如我们有一个Point类如下所示:- using System;<br>public class Point<br>{<br> public int x;<br> public int y;<br> public void Print()<br> {<br> Console.WriteLine("[{0},{1}]",x,y);<br> }<br> }
复制代码 先将其编译成Point.dll文件,然后我们需要在Reflect.cs文件中用到这个类型:
代码如下:- using System;<br>public class Reflect<br>{<br> public static void Main()<br> {<br> Point p=new Point();<br> p.x=100;<br> p.y=200;<br> p.Print();<br> }<br> }
复制代码 然后我们编译这个文件,会发现抛出异常,告诉我们不存在Point类型,也就是说Point是一个未知类型,编译器根本不知道它,那怎么办了,这里我们需要在编译时对Point程序集进行引用,这样才能让编译器知道它,在很多应用程序开发框架中在我们编译项目的时候框架会自动进行程序集的引用,但是在这里我们的编译工作是手动进行的,因此我们也需要手动的引用程序集。下面是编译命令:
csc /r oint.dll Reflect.cs
这样我们在编译Reflect.cs文件的过程中就实现了对Point程序集的引用,这样编译器就识别了程序集中Point类型信息。其实任何类型信息的使用都需要有程序集的引用,不然的话编译器会不认识这个类型,编译就无法通过。我们可能会想,我们在很多时候进行编译的时候并没有对哪个程序集进行引用么?不是没有,而是很多预定义的类型信息编译器会默认帮我们进行引用,不需要我们显示的进行引用,比如mscorlib程序集,它是.NET一个核心程序集,里面包含了很多常用的预定义的类型信息,因此C#编译器在编译的时候会默认对它进行引用,可能我们会想,我们怎么知道一段代码在编译的过程中它到底都引用了哪些程序集了,这里就需要借助于元数据,下面我们通过ildasm工具查看了编译好的Reflect.exe程序集中的元数据,我们只截取了其中一段进行说明。
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern Point
{
.ver 0:0:0:0
}
从这段元数据中我们可以看出,这个程序集中包含了对Point程序集和mscorlib程序集的引用。
利用反射实现延迟加载程序集
在上面所举的例子中,所有对程序集的引用都是在编译时进行的,因此效率会比较高。但是在某些特定的情况下,我们需要对程序集进行延迟加载,即将对程序集的引用由编译时推移到运行时,反射是一种很好的选择,在最开始我们讲过,反射为.NET类型提供了高度的动态能力,包括:元数据的动态查询、绑定与执行、动态代码生成,这些功能的实现都离不开元数据。下面我们看看反射的具体实现。
[code]using System;
using System.Reflection;
class Test
{
public static void Main(string[] args)
{
string assemblyName=args[0];
string typeName=args[1];
string fieldName1=args[2];
string fieldName2=args[3];
string methodName=args[4];
Assembly assembly=Assembly.Load(assemblyName); //手动加载程序集
Type type=assembly.GetType(typeName); //获取程序集中的类型
//查询
MemberInfo[] mis=type.GetMembers(); //获取类型中的成员信息
for(int i=0;i |