每个.NET程序集除了程序代码外都额外包含了元数据。元数据包含了程序集本身的信息,比如版本号,引用了什么程序集等。元数据也包含了程序集内所有类型的信息,包括其方法、属性和字段。使用.NET反射,你可以在运行时读取这些信息,并且可以动态地调用方法。

   让我们来看这样一个例子,它通过使用.NET反射读取和动态调用了一个方法。在这个示例中有一个Demo类,它带有方法Message以被动态调用。Demo类在程序集ReflectionLib.dll中。

 

namespace Samples.Reflection

{

   public class Demo

   {

   public void Message(string s)

   {

   System.Console.WriteLine(s);

   }

   }

}

我们有一个简单的控制台程序,其中有一个Test类,动态地调用了Demo类的Message方法。首先,含有Demo类的程序集通过Assembly类的LoadFrom静态方法来加载入内存,这个程序集的文件名来自于命令行参数,是在启动这个应用程序时传入的。

通过Assembly.LoadFrom方法返回的assembly对象,可以读取其中的元数据。方法GetType会返回一个用于表示Samples.Reflection.Demo的Type对象。如果你想读取此程序集的所有的类型,方法GetTypes会返回一个Type对象的数组。

调用方法t.GetMethod会返回方法自身的信息,表现(represented)于MethodInfo类中。通过MethodInfo对象,你可以读取方法的名称,得到关于参数的信息。通过MethodInfo的Invoke方法,你可以动态地调用此方法。因为实例方法需要在调用时有一个实例存在,所以用Activator.CreateInstance根据从程序集中获得的类型(前面得到的Type对象)创建了一个对象。Invoke方法允许你通过一个对象数组传递任意数量的参数到目标方法。Message方法只需要一个参数,所以传入了一个只包含一个对象的数组到Invoke方法中。

结果是,Message方法在控制台输出了字符串“Test”。

 

using System;

using System.Reflection;

 

class Test

{

   static void Main(string[] args)

   {

   if (args.Length != 1)

   {

   Console.WriteLine("filename needed");

   return;

   }

 

   string filename = args[0];

 

   Assembly assembly = Assembly.LoadFrom(filename);

   Type t = assembly.GetType("Samples.Reflection.Demo");

   MethodInfo mi = t.GetMethod("Message");

 

   object o = Activator.CreateInstance(t);

   object[] parameters = new object[] {"Test"};

   mi.Invoke(o, parameters);

   }

}

posted on 2010-06-30 16:00  davidding  阅读(495)  评论(0编辑  收藏  举报