反射概述 和Type类
1.反射的作用
简单来说,反射提供这样几个能力:1、查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata);2、迟绑定(Late-Binding)方法和属性。3、动态创建类型实例(并可以动态调用所创建的实例的方法、字段、属性)。序章中,我们所采用的那个例子,只是反射的一个用途:查看类型成员信息。接下来的几个章节,我们将依次介绍反射所提供的其他能力。
2.获取Type对象实例
反射的核心是Type类,这个类封装了关于对象的信息,也是进行反射的入口。当你获得了关于类型的Type对象后,就可以根据Type提供的属性和方法获取这个类型的一切信息(方法、字段、属性、事件、参数、构造函数等)。我们开始的第一步,就是获取关于类型的Type实例。获取Type对象有两种形式,一种是获取当前加载程序集中的类型(Runtime),一种是获取没有加载的程序集的类型。
我们先考虑Runtime时的Type,一般来说有三种获取方法:
2.1使用Type类提供的静态方法GetType()
比如我们想要获得Stream类型的Type实例,则可以这样:
Type t = Type.GetType("System.IO.Stream");
txtOutput.Text = t.ToString();
注意到GetType方法接受字符串形式的类型名称。
2.2 使用 typeof 操作符
也可以使用C# 提供的typeof 操作符来完成这一过程:
// 如果在页首写入了using System.IO; 也可以直接用 typeof(Stream);
Type t = typeof(System.IO.Stream);
这时的使用有点像泛型,Stream就好像一个类型参数一样,传递到typeof操作符中。
2.3 通过类型实例获得Type对象
我们还可以通过类型的实例来获得:
String name = "Jimmy Zhang";
Type t = name.GetType();
使用这种方法时应当注意,尽管我们是通过变量(实例)去获取Type对象,但是Type对象不包含关于这个特定对象的信息,仍是保存对象的类型(String)的信息。
3.Type类型 及 Reflection命名空间的组织结构
到现在为止,我已经多次提过Type封装了类型的信息,那么这些类型信息都包含什么内容呢?假设我们现在有一个类型的实例,它的名字叫做 demo,我们对它的信息一无所知,并通过下面代码获取了对于它的Type实例:
// 前面某处的代码实例化了demo对象
Type t = demo.GetType();
现在,我们期望 t 包含了关于 demo 的哪些信息呢?
3.1 demo的类型的基本信息
- 我们当然首先想知道 demo 是什么类型的,也就是 demo 的类型名称。
- 我们还想知道该类型位于什么命名空间下。
- 它的基类型是什么,以及它在.Net运行库中的映射类型。
- 它是值类型还是引用类型。
- 它是不是Public的。
- 它是枚举、是类、是数组、还是接口。
- 它是不是基础类型(int等)。
- 等等 ...
Type 提供了下面的属性,用于获取类型的基本信息,常用的有下面一些:
属 性 | 说 明 |
Name | 获取类型名称 |
FullName | 类型全名 |
Namespace | 命名空间名称 |
BaseType | 获取对于基类的Type类型的引用 |
UnderlyingSystemType | 在.Net中映射的类型的引用 |
Attributes | 获取TypeAttributes位标记 |
IsValueType | 是否值类型 |
IsByRef | 是否由引用传递 |
IsEnum | 是否枚举 |
IsClass | 是否类 |
IsInterface | 是否接口 |
IsSealed | 是否密封类 |
IsPrimitive | 是否基类型(比如int) |
IsAbstract | 是否抽象 |
IsPublic | 是否公开 |
IsNotPublic | 是否非公开 |
IsVisible | 是否程序集可见 |
等等... |
3.2 demon的类型的成员信息
- 我们可能还想知道它有哪些字段。
- 有些什么属性,以及关于这些属性的信息。
- 有哪些构造函数。
- 有哪些方法,方法有哪些参数,有什么样的返回值。
- 包含哪些事件。
- 实现了哪些接口。
- 我们还可以不加区分地获得它的所有 以上成员。
观察上面的列表,就拿第一条来说,我们想获取类型都有哪些字段,以及这些字段的信息。而字段都包含哪些信息呢?可能有字段的类型、字段的名称、字段是否public、字段是否为const、字段是否是read only 等等,那么是不是应该将字段的这些信息也封装起来呢?
实际上,.Net中提供了 FiledInfo 类型,它封装了关于字段的相关信息。对照上面的列表,类似的还有 PropertyInfo类型、ConstructorInfo类型、MethodInfo类型、EventInfo类型。而对于方法而言,对于它的参数,也会有in参数,out参数,参数类型等信息,类似的,在 System.Reflection 命名空间下,除了有上面的提到的那么多Info后缀结尾的类型,还有个ParameterInfo 类型,用于封装方法的参数信息。
最后,应该注意到 Type 类型,以及所有的Info类型均 继承自 MemberInfo 类型,MemberInfo类型提供了获取类型基础信息的能力。
在VS2005中键入Type,选中它,再按下F12跳转到Type类型的定义,纵览Type类型的成员,发现可以大致将属性和方法分成这样几组:
- IsXXXX,比如 IsAbstract,这组bool属性用于说明类型的某个信息。(前面的表格已经列举了一些。)
- GetXXXX(),比如GetField(),返回FieldInfo,这组方法用于获取某个成员的信息。
- GetXXXXs(),比如GetFields(),返回FieldInfo[],这组方法用户获取某些成员信息。
- 还有其他的一些属性和方法,等后面遇到了再说。
由于MemberInfo是一个基类,当我们获得一个MemberInfo后,我们并不知道它是PropertyInfo(封装了属性信息的对象)还是FieldInfo(封装了属性信息的对象),所以,有必要提供一个办法可以让我们加以判断,在Reflection 命名空间中,会遇到很多的位标记,这里先介绍第一个位标记(本文管用[Flags]特性标记的枚举称为 位标记),MemberTypes,它用于标记成员类型,可能的取值如下:
[Flags]
public enum MemberTypes {
Constructor = 1, // 该成员是一个构造函数
Event = 2, // 该成员是一个事件
Field = 4, // 该成员是一个字段
Method = 8, // 该成员是一个方法
Property = 16, // 该成员是一个属性
TypeInfo = 32, // 该成员是一种类型
Custom = 64, // 自定义成员类型
NestedType = 128, // 该成员是一个嵌套类型
All = 191, // 指定所有成员类型。
}
转自:http://www.cnblogs.com/JimmyZhang/archive/2008/02/17/1071372.html