元数据和反射
要使用反射,必须使用System.Reflection 命名空间
Type类
Type是一个抽象类,用来包含类型的特性,使用这个类的对象可以让我们获取程序使用的类型的信息
我们可以从Type对象中获取需要了解的有关类型的几乎所有信息
获取Type对象
object 类型包含了一个叫做GetType 的方法,它返回对实例的Type对象的引用。
Type t = myInstance.GetType();
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection; //必须使用的命名空间
namespace Csharpzuoye
{
class BaseClass
{
public int BaseField = 0;
}
class DerivedClass:BaseClass
{
public int DrivedFiled = 0;
}
class Program
{
static void Main()
{
var bc = new BaseClass();
var dc = new DerivedClass();
BaseClass[] bca = new BaseClass[] { bc, dc };
foreach(var v in bca)
{
Type t = v.GetType(); //获取类型
Console.WriteLine("Object type: {0}", t.Name);
FieldInfo[] fi = t.GetFields(); //获取字段数据
foreach (var f in fi)
Console.WriteLine(" Field : {0}", f.Name);
Console.WriteLine();
}
}
}
}
我们可以使用typeof运算符来获取Type对象。只需要提供类型名作为操作数,它就会返回Type对象的引用
什么是特性
特性是一种允许我们向程序的程序集增加元数据的语言结构。它是用于保存程序结构信息的某种特殊类型的类
应用特性
特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集。我们可以通过把特性应用到结构来实现
预定义的保留的特性
在学习如何定义自己的特性之前,先介绍几个.NET 预定义特性
Obsolete 特性
可以使用Obsolete特性将程序结构标注为过期的,并且在代码编译时显示有用的警告信息
Conditional 特性
Conditional 特性允许我们包括或排斥特定方法的所有调用。
调用者信息特性
调用者信息特性可以访问文件路径,代码行数,调用成员的名称等源代码信息
DeBuggerStepThrough特性
我们在单步调试代码时,常常希望调试器不要进入某些方法。DeBuggerStepThrough特性告诉调试器在执行目标代码时不要进入其中调试而是直接执行
其他预定义特性
这里使用的是不带 Attribute 后缀的短名称
有关应用特性的更多内容
多个特性
我们可以为单个结构应用多个特性
其他类型的目标
除了类还可以将特性应用到诸如字段和属性等其他程序结构
全局特性
自定义特性
特性只是某个特殊类型的类
声明自定义特性
总体来说,声明一个特性类和声明其他类一样
使用特性的构造函数
指定构造函数
当我们为目标应用特性时,其实是在指定应该使用哪个构造函数来创建特性的实例。列在特性应用中的参数其实就是构造函数的参数
使用构造函数
我们不能显式调用构造函数,特性的实例创建后,只有特性的消费者访问特性时才能调用构造函数。应用一个特性时一条声明语句,它不会决定什么时候构造特性类的对象
构造函数中的位置参数和命名参数
和普通类的方法与构造方法类似,特性的构造方法同样可以使用位置参数和命名参数
构造函数需要的任何位置参数都必须放在命名参数之前
限制特性的使用 AttributeUsage特性
有一个很重要的预定义特性可以用来应用到自定义特性上,那就是AttributeUsage 特性,我们可以用它来限制特性使用在某个目标类型上