这里简要介绍type和assembly
自定义特性
为了理解编写自定义特性的方式,应了解一下在编译器遇到代码中某个应用自定义特性的元素时,该如何处理。
[AttributeUsage(AttributeTargets.Property,AllowMultiple =false,Inherited =false)]
public class FieldNameAttribute:Attribute
{
public string name;
public FieldNameAttribute(string name)
{
this.name = name;
}
}
[FieldName("text")]
public string text { get; set; }
这段代码中定义一个FieldNameAttribute的类。当C#编译器发现这个属性(text)应用了一个FieldName特性时,首先会把字符串Attribute追加到这个名称的后面,然后在其搜索路径的所有名称空间中搜索有指定名称的类。但要注意,如果用一个特性标记数据项,而该特性的名称以字符串Atribute结尾,编译器就不会把该字符串加到组合名称中,而是不修改该特性名。
[FieldName("text")]
public string text { get; set; }
等价于
[FieldNameAttribute("text")]
public string text { get; set; }
1、AttributeUsage
要注意的第一个问题是特性类本身用一个特性--System.AttributeUsage特性来标记。这是Microsoft定义的一个特性,C#编译器为它提供了特殊的支持。AttributeUsage主要用于标记自定义特性应用到哪些类型的程序元素上。这些信息由它的第一个参数给出,该参数是必选的,其类型是枚举类型AttributeTarget。在上面的示例中,指定FieldName特性只能应用到属性上。AttributeTarget枚举的成员如下:
ALL Assembly Class Constructor Delegate Enum GenericParameter Interface Method Module Parameter Property Return Value Struct
这个列表列出了可以应用该特性的所有程序元素。注意在把特性应用到程序元素上时,应把特性放在元素前面的方括号中。但是,在上面的列表中,有两个值不对任何程序元素:Assembly Module。 特性可以应用到整个程序集或模块中,而不是应用到代码中的一个元素上,在这种情况下,整个特性可以放在源代码中的任何地方,但需要关键字Assembly或Module作为前缀:
[Assembly:SomeAssemblyAttribute(Parameters)]
[Module:SomeAssemblyAttribute(Parameters)]
在指定自定义特性的有效目标元素时,可以使用按位OR运算符把这些值组合起来。例如:
[AttributeUsage(AttributeTargets.Property|AttributeTargets.Method,AllowMultiple =false,Inherited =false)]
public class FieldNameAttribute:Attribute
{
public string name;
public FieldNameAttribute(string name)
{
this.name = name;
}
}
也可以使用AttributeTargets.All指定特性可以应用到所有类型的程序元素上。AttributeUsage还包含另外两个参数:AllowMultiple和Inherited。它们用不同的语法来指定:
AllowMultiple参数表示一个特性是否可以多次应用到同一项上。Inherited参数设置为true,就表示应用到类或接口上的特性也可以应用到所有派生的类或接口上。
2、指定特性参数
编译器会检查传递给特性的参数,并查找该特性中带这些参数的构造函数。找到此构造函数,反射会从程序集中读取元数据(特性),并实例化他们表示的特性类。因此,需要确存在这样的构造函数,不然编译错误。
3、指定特性的可选参数
在AttributeUsage特性中,可以使用另一种语法,把可选参数添加到特性中。这种语法指定可选参数的名称和值,它通过特性类中的公共属性或字段起作用。
[FieldName("text", comment="12542231")]
public string text { get; set; }
public class FieldNameAttribute:Attribute
{
public string comment;
public string Comment { get { return comment; } set { comment = value; } }
.........
}
编译器识别第二个参数的语法,并且不会把这个参数传递给FieldNameAttribute类的构造函数,而是查找一个有该名称的公共属性或字段。
反射
通过System.Type类可以访问关于任何数据类型的信息。我们以前把Type看作一个类,实际上它是一个抽象的基类。只要实例化一个Type对象,实际上就是实例化了Type的一个派生类。尽管一般情况下派生类只提供各种Type方法和属性的不同重载,但是这些方法和属性返回对应数据类型的正确数据,Type有与每种数据类型对应的派生类。他们一般不添加新的方法或属性。通常有三种方式:
a、使用c#的typeof运算符:Typet=typeof(double);
b、使用GetType()方法,所有的类都会从System.object继承这个方法。
c、还可以调用Type类的静态方法GetType()
Type的属性:
Type的属性可以分为三类:首先,许多属性都可以获取包含与类相关的各种名称的字符串,如:Name、FullName、Namespace. 其次,属性还可以进一步获取Type对象的引用,这些引用表示相关的类。如:BaseType、UnderlyingSystemType。 还有一类就是许多的布尔属性表示这种类型是一个类还是一个枚举等。这些特性包括:IsAbstract、IsArray、IsClass、IsEnum、IsInterface、IsPointer、IsPrimitive、IsPublic、IsSeadled、IsValueType.
Type的方法:
System.Type的大多数方法都用于获取对应数据类型的成员信息:构造函数、属性、方法和事件等。他有许多方法,但他们都有相同的模式。例如:GetMethod()和GetMethods()。
Assembly类
Assembly类它允许访问给定程序集的元数据,它也包含可以加载和执行程序集的方法。在使用Assembly实例做一些工作前,需要把相应的程序集加载到正在允许的进程中。为此,可以使用静态成员Assembly。Load()或Assembly.LoadFrom()。这两个方法的区别是Load()方法的参数是程序集的名称,运行库会在各个位置上搜索该程序集,试图找到该程序集,这些目录包括本地目录和全局程序集缓存。而LoadFrom()方法的参数是程序集完整路径名,他不会在其他位置搜索该程序集:
Assembly assemblys1 = Assembly.Load("textassembly");
Assembly assemblys2 = Assembly.LoadFrom(@"C:My Project extassembly");
1、获取在程序集中定义的类型的详细信息
Assembly 类的一个功能是它可以获得在相应程序集中定义的所有类型的详细信息,只要调用Assembly.GetType()方法,他就可以返回一个包含所有类型的详细信息的System.Type引用数组,就可以按照Type处理的方式引用了。
2、获取自定义特性的详细信息
用于查找在程序集或类型中定义了什么自定义特性的方法取决于与该特性相关的对像类型。Attribute[] aa = Attribute.GetCustomAttributes(assemblys2);
************这是相当重要的,以前你可能想知道,在定义自定义特性时,为什么必须费尽周折为他们编写类,以及为什么没有更简单的语法。答案就在于此,自定义特性确实与对象一样,加载了程序集后,就可以读取这些特性对象,查看它们的属性,调用他们的方法。**************
GetCustomAttributes()方法用于获取程序集的特性,它有两个重载方法:第一个参数是程序集的引用,第二个参数是Type对象。
Attribute[] aa = Attribute.GetCustomAttributes(assemblys2,typeof(FieldNameAttribute));