反射---Reflection学习

   在软件开发中,常常需要一些动态的操作。比如根据用户输入的信息动态的创建一个类或者调用类中的方法。

     反射概述

       程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。可以使用反射动态的创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或者访问其字段和属性。

  反射通常有以下用途:

  1. 使用Assembly定义和加载程序集。加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
  2. 使用Module了解:包含模块的程序集以及模块中的类,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
  3. 使用ConstructorInfo了解:构造函数的名称、参数、访问修饰符和实现详细信息(如abstract或virtual)。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。
  4. 使用MethodInfo了解:方法的名称、参数、访问修饰符和实现详细信息(如abstract或virtual)。使用Type的GetMethods或GetMethod方法来调用特定的方法。
  5. 使用FieldInfo了解:字段的名称、访问修饰符和实现详细信息(如static),并获取或设置字段值。
  6. 使用EventInfo了解:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
  7. 使用PropertyInfo了解:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
  8. 使用ParameterInfo了解:参数的名称、数据类型、参数是输入参数还是输出参数、,以及参数在方法签名中的位置。

   查看类型信息

   当反射请求加载的类型时,CLR为它创建一个Type。可以使用Type对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。

  1. 在使用Assembly.GetType或Assembly.GetTypes时,传入所需类型的名称,可以从尚未加载的程序集中获取Type对象。
  2. 使用Type.GetType可从已加载的程序集中获取Type对象。
  3. 使用Module.GetType和Module.GetTypes可获取模块Type对象。

   下面实例说明如何从已加载的程序集中获取Type对象。

   1:  // Loads an assembly using its file name.
   2:  Assembly a = Assembly.LoadFrom ("MyExe.exe");
   3:  // Gets the type names from the assembly.
   4:  Type [] types2 = a.GetTypes ();
   5:  foreach (Type t in types2)
   6:  {
   7:      Console.WriteLine (t.FullName);
   8:  }

在获取了一个Type对象之后,可以采用很多方法来获取与该类型有关的成员的有关信息。如:Type.GetMembers方法获取有关该类型的所有成员信息。

下面示例显示如何列出一个类的构造函数。

   1:  // This program lists all the public constructors 
   2:  // of the System.String class.
   3:  using System;
   4:  using System.Reflection;
   5:  class ListMembers {
   6:      public static void Main(String[] args) {
   7:          Type t = typeof(System.String);
   8:          Console.WriteLine ("Listing all the public constructors of the {0} type", t);
   9:          // Constructors.
  10:          ConstructorInfo[] ci = t.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
  11:          Console.WriteLine ("//Constructors");
  12:          PrintMembers (ci);
  13:      }
  14:      public static void PrintMembers(MemberInfo [] ms) {
  15:          foreach (MemberInfo m in ms) {
  16:              Console.WriteLine ("{0}{1}", "     ", m);
  17:          }
  18:          Console.WriteLine();
  19:      }
  20:  }
    
  动态加载和使用类型
  在写这个内容之前,先写一些早期绑定、动态绑定和后期绑定。这里的绑定指的是与类之间建立某种联系的过程。
  早期绑定,举个简单例子,我们写一个控制台程序:
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using ClassLibraryTest;
   6:   
   7:  namespace EarlyBindingDemo
   8:  {
   9:      class Program
  10:      {
  11:          static void Main(string[] args)
  12:          {
  13:              Class1 clazz = new Class1();
  14:              Console.Write(clazz.getHello());
  15:              Console.ReadKey();
  16:          }
  17:      }
  18:  }

    Class1文件为:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  namespace ClassLibraryTest
   7:  {
   8:      public class Class1
   9:      {
  10:          public string getHello() 
  11:          {
  12:              return "Hello!";
  13:          }
  14:      }
  15:  }

     在项目EarlyBindingDemo中添加对Class1.dll的引用,然后在Rrogram里实例化Class1,调用Class的getHello方法。经过编译器编译后,这样一个过程就已经卸载程序集里面了,这就叫做“早期绑定”。

       如果EarlyBindingDemo是在完全未知Class1的情况下去调用Class1,这就叫做“后期绑定”。

   1:  using System; 
   2:  using System.Collections.Generic;  
   3:  using System.Text;  
   4:  using System.Reflection;  
   5:  using System.Windows.Forms; 
   6:   namespace EarlyBindingDemo  
   7:   {  
   8:       class Program 
   9:       {  
  10:           static void Main(string[] args)  
  11:           { 
  12:               Assembly assembly = Assembly.LoadFile(Application.StartupPath + \\ClassLibrary1Test.dll);    //加载指定路径上的程序集文件的内容。
  13:               Type type = assembly.GetType("ClassLibraryTest.Class1");  
  14:               MethodInfo methodInfo = type.GetMethod("Hello"); 
  15:               object obj = assembly.CreateInstance("ClassLibraryTest.Class1");//从此程序集中查找指定的类型创建它的实例。
  16:               Console.WriteLine(methodInfo.Invoke(obj,null));
  17:           } 
  18:        }
  19:    }

     而“动态绑定”就是指建立了部分联系,一般是在虚方法或者抽象方法调用时,多态机制会在执行期间根据实际对象来确定要执行的代码。

       自定义绑定

       当通过反射进行后期绑定时,必须使用自定义绑定来控制绑定。Binder类提供了对成员选择和调用的自定义控制。利用自定义绑定,可以在运行时加载程序集,获取有关该程序集中类型的信息,然后对该类型调用方法或访问该类型的字段或属性。如果在编译时不知道对象的类型时,就可以使用这种方法。

      InvokeMember 和 CreateInstance

      使用 Type.InvokeMember 可调用类型的成员。各个类(如 System.ActivatorSystem.Reflection.Assembly)的 CreateInstance 方法是 InvokeMember 的特殊形式,它们可新建特定类型的实例。Binder 类用于在这些方法中进行重载决策和参数强制。

posted @ 2009-12-22 19:05  唐颖  阅读(234)  评论(0编辑  收藏  举报