元数据与反射
- 程序是用来处理数据的,文本和特性都是数据;而程序本身(类的定义和BLC中类)这些也都是数据。
- 有关程序以及其类型的数据被称为元数据(metadata),他们保存在程序的程序集中。
- 程序在运行时,可以查看其它程序集或其本身的元数据。一个运行的程序查看本身的元数据或者其它程序集的元数据的行为称为反射。
Type类
首先,对于预定义的类型(int,long,string等)、BCL中的类型(Console,IEnumerable等)和用户自定义类型(MyClass等),每种类型都有自己的成员和特性。
在BCL中,声明了一个叫做Type的抽象类,它被设计用来包含类型的特性。使用这个类的对象能让我们获取程序使用的类型的信息。
由于Type是抽象类,因此不能利用它去实例化对象。关于Type类:
- 对于程序中用到的每一个类型,CLR都会创建一个包含这个类型的Type类型的对象。
- 程序中用到的每一个类型都会关联到独立的Type类的对象。
- 不管创建的类型有多少个示例,只有一个Type对象会关联到所有这些实例。
获取Type对象
class MyClass
{
private int id;
private int age;
public int number;
public string Name1{get;set;}
public string Name2{get;set;}
public string Name3{get;set;}
public void Test1(){
}
public void Test2(){
}
}
//每一个类对应一个type对象,这个type对象存储了这个类有哪些方法、字段、成员
MyCLass my = new MyClass();//一个类中的数据是存储在对象中的,但是type对象之存储类的成员
Type type = my.GetType();//通过对象获取这个对象所属的类的Type对象
Console.WriteLine(type.Name);//获取类的名字
Console.WriteLine(type.Namespace);//获取所在的命名空间
Console.WriteLine(type.Assembly);//获取所在的程序集
//实际上,type对象和my对象是没有什么关系的
//仅仅是通过my对象获取对象所在类的Type对象而已
//获取字段
FieldInfo[] array = type.GetFields();//只能获取public字段
foreach(FieldInfo info in array)
Console.Write(info.Name + " ");
//输出为number
//获取属性
PropertyInfo[] array2 = type.GetProperties();
foreach(PropertyInfo info in array2)
Console.Write(info.Name + " ");
//输出为Name1 Name2 Name3
//获取方法
MethodInfo[] array3 = type.GetMethods();
foreach(MethodInfo info in array3)
Console.Write(info.Name + " ");
//输出为:
//get_Name1 set_Name1 get_Name2 set_Name2 get_Name3 set_Name3 Test1 Test2 ToString Equals GetHashCode GetType
//前面几个get和set方法是定义属性时系统所生成的
//最后的三个方法是继承自父类Object的方法
通过type对可以获得它所对应的类的所有公有的成员。
特性
特性(attribute),是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类。
我们将应用了特性的程序结构叫做目标。
设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者。
.NET预定了很多特性,我们也可以声明自定义特性。
创建和使用特性
- 我们在源代码中将特性应用于程序结构。
- 编译器获取源代码并从特性产生元数据,然后把元数据放到程序集中。
- 消费者程序可以获取特性的元数据以及程序中其他组件的元数据。注意,编译器同时生产和消费特性。
关于特性的命名规范,特性名使用Pascal命名法(首字母大写),并且以Attribute后缀结尾,当为目标应用特性时,我们可以不使用后缀。例如对于SerializableAttribute和MyAttributeAttribute这两个特性,我们把他们应用到结构是可以使用Serializable和MyAttribute。