大多数程序都要处理数据,包括读、写、操作和显示数据。然而,对于某些程序来说,它们操作的不是数字、文本或图形,而是程序和程序类型本身的信息。
有关程序及其类型的数据被称为元数据(metadata),它们保存在程序的程序集中。
程序在运行时,可以查看其他程序集或其本身的元数据。一个运行的程序查看本身的元数据和其他程序的元数据的行为叫做反射(reflection)。
反射提供了封装程序集、模块和类型的对象(Type类型)。可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。如果代码中使用了特性,可以利用反射对它们进行访问。
反射的概念:
程序正在运行时,可以查看其它程序集或者自身的元数据。
—个运行的程序查看本身或者其它程序的元数据的行为就叫做反射。
通俗来讲,在程序运行时,通过反射可以得到其它程序集或者自己程序集代码的各种信息类,函数,变量,对象等等,实例化它们,执行它们,操作它们。
反射的作用:
因为反射可以在程序编译后获得信息,所以它提高了程序的拓展性和灵活性
1.程序运行时得到所有元数据,包括元数据的特性
2.程序运行时,实例化对象,操作对象
3.程序运行时创建新对象,用这些对象执行任务
要注意的是,使用反射时,必须使用System.Reflection命名空间。
BCL声明了一个叫做Type的抽象类,它被设计用来包含类型的特性,使用这个类的对象能让我们获取程序使用的类型的信息。
由于Type是抽象类,因此它不能有实例,而是在运行时CLR创建从Type(RuntimeType)派生的类的实例。Type包含了类型信息,当我们要访问这些实例时,CLR不会返回派生类的引用而是返回Type基类的引用。为了简单起见,下面篇幅中我会把引用所指向的对象称为Type类型的对象。
Type类的重要事项:
对于程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象。
程序中用到的每一个类型都会关联到独立的Type类型的对象。
不管创建的类型有多少个实例,只有一个Type对象会关联到所有这些实例。
我们可以使用GetType方法和typeof运算符来获取Type对象。object类型包含了一个叫做GetType的方法,它返回对实例的Type对象的引用。由于每一个类型最终都是从object继承的,所以我们可以在任何类型对象上使用GetType方法来获取它的Type对象。
举个例子:
using System; using System.Reflection; namespace Type类使用 { class Base { public int BaseField = 0; } class Derived : Base { public int DerivedField = 0; public int change { set; get; } } class Program { static void Main(string[] args) { Base b = new Base(); Derived d = new Derived(); Base[] bd = new Base[] { b, d }; foreach(var val in bd) { Type t = val.GetType(); //获取类型 Console.WriteLine("object type:{0}", t.Name); FieldInfo[] fi = t.GetFields(); //获取字段信息 foreach(var f in fi) { Console.WriteLine(" Field: {0}", f.Name); } } Console.ReadKey(); } } }