C# 高级编程(笔记6)
第14章 反射
1.自定义特性(Attribute)
编译器在遇到代码中某个应用了自定义特性的元素时的处理过程:
eg: [StringLength(50, ErrorMessageResourceType = typeof(res), ErrorMessageResourceName = "MAX_USER_NAME_LENGTH")] public String UName { get; set; }
//当C#编译器发现这个属性(property)应用了一个StringLength特性时,首先会把字符串Attribute追加到这个名称的后面,形成一个组合名称StringLengthAttribute,然后在其搜索路径的所有名称空间(即在using语句中提及的名称空间)中搜索有指定名称的类。但要注意,如果用一个特性标记数据项,而该特性的名称以字符串Attribute结尾,编译器就不会把该字符串加到组合名称中,而是不修改该特性名。
//编译器会找到含有该名称的类,且这个类直接或间接派生自System.Attribute。编译器还认为这个类包含控制特性用法的信息,特别是:
a.特性可以应用到哪些类型的程序元素上(类、结构、属性和方法等)
b.它是否可以多次应用到同一个程序元素上
c.特性在应用到类或接口上时,是否由派生类和接口继承
d.这个特性有哪些必选和可选参数
----如果编译器找不到对应的特性类,或者找到一个这样的特性类,但使用特性的方式与特性类中的信息不匹配,编译器就会产生一个编译错误。
2.AttributeUsage 特性类
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] public class FieldNameAttribute : Attribute { public FieldNameAttribute() { } }
//一个自定义的特性类FieldNameAttribute本身再用一个System.AttributeUsage特性类来标记。AttributeUsage特性类主要用于标识自定义特性可以应用到哪些类型的程序元素上。这些信息由它的第一个参数给出,该参数是必选的,其类型是枚举类型AttributeTargets。
//AttributeTargets枚举的成员中有两个值不对应于任何程序元素:Assembly和Module,表明该特性可以应用到整个程序集或模块中,而不是应用到代码中的一个元素上,在这种情况下,这个特性可以放在源代码的任何地方,但需要用关键字assembly或module作为前缀
[assembly: SomeAssemblyAttribute(Parameters)]
[module: SomeAssemblyAttribute(Parameters)]
3.System.Type类
Type类是一个抽象基类,只要实例化一个Type对象,实际上就实例化了Type的一个派生类,Type有与每种数据类型对应的派生类。
通常,获取指向任何给定类型的Type引用有3种常用方式:
a.使用C#的typeof运算符
//获取编译时阶段某一类型的System.Type对象
//typeof()参数只能是构架中已经定义好了的类型和自定义类型,不能是实例
Type t = typeof(double); b.使用GetType()方法,所有的类都会从System.Object继承这个方法 //获取运行时阶段当前实例的类型
//GetType()是实例方法 double d = 10.0; Type t = d.GetType(); c.调用Type类的静态方法GetType() Type t = Type.GetType("System.Double");
//Type是许多反射功能的入口,它实现许多方法和属性,可以使用Type确定数据的类型,但不能使用它修改该类型
Type还可以获取在其中定义该类型的程序集的引用:
Type t = typeof(Vector); Assembly ass = new Assembly(t);
4.Assembly 类
Assembly类允许访问给定程序集的元数据,它也包含可以加载和执行程序集的方法【假定该程序集是可执行的】。与Type类一样,Assembly类包含非常多的方法与属性。
在使用Assembly实例做一些工作前,需要把相应的程序集加载到正在运行的进程中。为此,可以使用静态成员Assembly.Load()或Assembly.LoadFrom()。
a.Assembly.Load() ---- 该方法的参数是程序集的名称,运行库会在各个位置上搜索该程序集,这些位置包括本地目录和全局程序集缓存
b.Assembly.LoadFrom() ---- 该方法的参数是程序集的完整路径名,它不会在其他位置搜索该程序集
Assembly ass1 = Assembly.Load("SomeAssembly"); Assembly ass2 = Assembly.LoadFrom(@"C:\My Projects\software\SomeotherAssembly");
加载完一个程序集后,就可以使用它的各种属性进行查询,如:
a.查找在程序集中定义的类型 Type[] types = theAssembly.GetTypes(); foreach(Type t in types) { ... } b.查找自定义特性 //得到指定程序集中所有自定义特性 Attribute[] attr = Attribute.GetCustomAttributes(theAssembly);