《Illustrated C# 2012, 4th Edition》Daniel M. Solis 第24章 反射和特性 笔记
有关程序及其类型的数据称为元数据,保存在程序集中。
程序运行时,查看本身或其他程序集元数据的行为称为反射。
使用反射,必须using System.Reflection命名空间。
Type类是一个抽象类,被设计用来包含类型信息。
程序运行时,CLR会为每一个用到的类型,都创建一个从Type派生的类的实例,然后返回这个实例的Type类的引用。
因此每一个类型都对应一个Type类对象。不论一个类型有多少实例,它们都对应同一个Type类对象。
从Type类对象可以获取到对应类型的几乎所有信息:
object类型对象的GetType()方法和typeof运算符都返回一个Type类对象。typeof运算符的参数为类型名。
特性(attribute)允许向程序集添加元数据。
.NET预定了很多特性,支持声明自定义特性。
根据惯例,特性名使用Pascal命名法并且以Attribute后辍结尾。当为目标应用特性时,可以不使用后辍。
特性可以带参数,也可以不带参数:
Obsolete特性标注一个程序结构为过期,在编译时输出一条警告或错误信息。Obsolete特性有两个重载:
[Obsolete("Use method SuperPrintOut")]
static void PrintOut(string str)
{ ...
输出警告信息:
'AttrObs.Program.PrintOut(string)' is obsolete: 'Use method SuperPrintOut'
[Obsolete("Use method SuperPrintOut", true)]
static void PrintOut(string str)
{ ...
输出错误信息,内容与之前相同。
Conditional特性只能用于方法,参数是一个字符串表示一个编译符号。当编译符号定义时,与普通方法相同。当编译符号未定义时,编译器在程序集中删除所有调用这个方法的代码,但不会删除这个方法的定义。
调用者信息特性:CallerFilePath、CallerLineNumber和CallerMemberName分别用于获取文件路径、代码行数、调用者名称。
调用者信息特性只能用于可选参数,用法如下:
DebuggerStepThrough用于告诉编译器调试时,不进入标注的程序结构内部。
DebuggerStepThrough只能用于类、结构、方法或访问器。
其他重要的预定义特性:
一个结构可以应用多个特性,有两种形式:
[Serializeble]
[MyAtrribute("Simple class", "Version 3.57")]
[MyAtrribute("Simple class", "Version 3.57"), Serializable]
应用特性时还可以显式标注应用到的目标结构,例如:
[method: MyAttribute("Prints out a message.", "Version 3.6")]
[return: MyAttribute("This value represents ...", "Version 2.3")]
public long Return Setting()
{ ...
特性的支持以下目标:
- typevar表示泛型结构的类型参数。
assembly和module表示程序集和模块,必须写在任何命名空间之外,通常写在AssemblyInfo.cs文件中。
特性类是派生自System.Atrribute的类。
特性类按惯例以Attribute结尾。
特性类建议声明为密封类。
特性类的public成员只能是字段、属性、构造函数。
特性类必须至少有一个public的构造函数,应用特性就是指定要使用的构造函数,构造函数的实参必须是编译时能确定的值。
特性的构造函数不是在应用特性时调用,应用特性只是将特性与目标关联,并指定需要构造特性时,使用哪个构造函数。
如果特性的构造函数是无参数,以下两种形式等价:
[MyAttr]
class SomeClass ...
[MyAtrr()]
class OtherClass ...
特性的构造函数支持命名参数。
预定义特性AttributeUsage可以限制特性类使用的目标,用法如下:
[AtrributeUsage(AttributeTarget.Method)]
public sealed class MyAtrributeAttribute : System.Attribute
{ ...
AttributeUsage的public属性:
AttributeUsage的构造函数接受一个AttributeTarget枚举类型参数用于设置ValidOn属性,枚举之间可以组合:
AttributeUsage的构造函数还接受两个可选的命名参数用于设置Inherited和AllowMutiple属性:
[AtrributeUsage(AttributeTarget.Class, Inherited = false, AllowMultiple = false)]
public sealed class MyAtrributeAttribute : System.Attribute
{ ...
Type对象的IsDefined()方法可以检测某个特性是否应用于某个类型。
IsDefined()方法接受两个参数,第一个是用于检测的特性类的Type对象,第二个参数是布尔,用于指定是否沿继承树查找这个特性,当为true时表示沿继承树搜索。
Type对象的GetCustomAttributes()方法,返回应用到指定程序结构的特性的数组,返回object数组,需要强转为特性类访问。GetCustomAttributes()方法接受一个布尔参数,用于指定是否沿继承树搜索,当为true时表示是。