转自:http://www.cnblogs.com/-dawn/archive/2012/09/29/2708053.htmlcss
介绍
html
Attributes是一种新的描述信息,咱们既可使用attributes来定义设计期信息(例如帮助文件,文档的URL),还能够用attributes定义运行时信息(例如,使XML中的元素与类的成员字段关联起来)。咱们也能够用attributes来建立一个“自描述”的组件。在这篇指南中咱们将明白怎么建立属性并将其绑定至各类语言元素上,另外咱们怎样在运行时环境下获取到attributes的一些信息。c#
定义ide
MSDN 中作以下定义(ms-help://MS.MSDNQTR.2002APR.1033/csspec/html/vclrfcsh ARP spec_17_2.htm)函数
"An attribute is a piece of additional declarative information that is specified for a declaration." 学习
使用预约义Attributesthis
在c#中已有一小组预约义的attributes,在咱们学习怎样建立自定义attributes前,先来了解下在咱们的代码中使用那些预约义的attributes.
spa
using System; publicclass AnyClass { [Obsolete( "Don't use Old method, use New method", true)] staticvoid Old( ) { } staticvoid New( ) { } publicstaticvoid Main( ) { Old( ); } }
仔细看下该实例,在该实例中咱们用到了”Obsolete”attribute,它标记了一个不应再被使用的语言元素( 译者注:这里的元素为方法) ,该属性的第一个参数是string类型,它解释为何该元素被荒弃,以及咱们该使用什么元素来代替它。实际中,咱们能够书写任何其它文原本代替这段文本。第二个参数是告诉编译器把依然使用这被标识的元素视为一种错误,这就意味着编译器会所以而产生一个警告。翻译
当咱们试图编译上面的上面的程序,咱们会获得以下错误:设计
AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'
开发自定义Attributes
如今咱们即将了解怎么开发自定义的attributes。这儿有个小小处方,有它咱们就能够学会建立自定义的attributes。
在C#中,咱们的attribute类都派生于System.Attribute类( A class that derives from the abstract class System.Attribute, whether directly or indirectly, is an attribute class. The declaration of an attribute class defines a new kind of attribute that can be placed on a declaration ) ,咱们就这么行动吧。
using System;
publicclass HelpAttribute : Attribute
{
}
无论你是否相信我,就这样咱们就已经建立了一个自定义 attribute。如今就能够用它来装饰咱们的类了,就像咱们使用obsolete attribute同样。
[Help()]
publicclass AnyClass
{
}
注意:按惯例咱们是用”Attribute“做为attribute类名的后缀,然而,当咱们当咱们把attribute绑定到某语言元素时,是不包含“Attribute“后缀的。编译器首先在System.Attribute的继承类中查找该attribute,若是没有找到,编译器会把“Attribute“追加到该attribute的名字后面,而后查找它。
可是迄今为止,该attribute没有任何用处。为了使它有点用处,让咱们在它里面加点东西吧。
using System; publicclass HelpAttribute : Attribute { public HelpAttribute(String Descrition_in) { this.description = Description_in; } protected String description; public String Description { get { returnthis.description; } } [Help( "this is a do-nothing class")] publicclass AnyClass { }
在上面的例子中,咱们在attribute类中添加了一个属性,在最后一节中,咱们将在运行时查询该属性。
定义或控制自定义Attribute的用法
AttributeUsage类是另外一预约义类( 译者注:attribute类自己用这个atrribute System.AttributeUsage来标记),它将帮助咱们控制咱们自定义attribute的用法,这就是,咱们能为自定义的attribute类定义attributes。
它描述了一个自定义attribute类能被怎样使用。
AttributeUsage提供三个属性,咱们能将它们放置到咱们的自定义attribute类上,第一个特性是:
ValidOn
经过这个属性,咱们能指定咱们的自定义attribute能够放置在哪些语言元素之上。这组咱们能把自定义attribute类放置其上的语言元素被放在枚举器AttributeTargets中。咱们可使用bitwise( 译者注:这个词不知道怎么翻译好,但他的意思是能够这么用 :[AttributeUsage (( AttributeTargets)4 , AllowMultiple =false, Inherited =false )], 4表明就是 “ class ” 元素,其它诸如 1 表明“ assembly ”, 16383 表明“ all ”等等 ) 或者”.”操作符绑定几个AttributeTargets值。(译者注:默认值为AttributeTargets.All)
AllowMultiple
该属性标识咱们的自定义attribte能在同一语言元素上使用屡次。( 译者注:该属性为bool类型,默认值为false,意思就是该自定义attribute在同一语言元素上只能使用一次)
Inherited
咱们可使用该属性来控制咱们的自定义attribute类的继承规则。该属性标识咱们的自定义attribute是否能够由派生类继承。((译者注:该属性为bool类型,默认值为false,意思是不能继承)
让咱们来作点实际的东西吧,咱们将把AttributeUsageattribute 放置在咱们的help attribute 上并在它的帮助下,咱们来控制help attribute的用法。
using System; [AttributeUsage(AttributeTargets.Class, AllowMultiple =false, Inherited =false )] publicclass HelpAttribute : Attribute { public HelpAttribute(String Description_in) { this.description = Description_in; } protected String description; public String Description { get { returnthis.description; } }
首先咱们注意 AttributeTargets.Class. 它规定这个help attribute 只能放置在语言元素”class”之上。这就意味着,下面的代码将会产生一个错误。
AnyClass.cs: Attribute 'Help' is not valid on this declaration type.
It is valid on 'class' declarations only.
如今试着把它绑定到方法。
[Help("this is a do-nothing class")] publicclass AnyClass { [Help( "this is a do-nothing method")] //error publicvoid AnyMethod() { } }
咱们可使用 AttributeTargets.All来容许Help attribute 能够放置在任何预约义的语言元素上,那些可能的语言元素以下:
Assembly,
Module,
Class,
Struct,
Enum,
Constructor,
Method,
Property,
Field,
EVE nt,
Interface,
Parameter,
Delegate,
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | EVE nt | Interface | Parameter | Delegate,
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | EVE nt | Delegate | Interface )
~ 如今考虑下AllowMultiple = false. 这就规定该attribute 不能在同一语言元素上放置屡次.
[Help("this is a do-nothing class")]
[Help( "it contains a do-nothing method")]
publicclass AnyClass
{
[Help( "this is a do-nothing method")] //error
publicvoid AnyMethod()
{
}
}
它产生了一个编译错误:
AnyClass.cs: Duplicate 'Help' attribute
Ok!如今咱们该讨论下最后那个属性了,”Inherited”, 指出当把该attribute放置于一个基类之上,是否派生类也继承了该attribute。若是绑定至某个attribute类的”Inherited”被设为true,那么该attribute就会被继承,然而若是绑定至某个attribute类的”Inherited”被设为false或者没有定义,那么该attribute就不会被继承。
让咱们假设有以下的类关系。
[Help("BaseClass")]
publicclass Base
{
}
publicclass Derive : Base
{
}
咱们有四种可能的绑定 :
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
第一种状况
若是咱们查询(咱们将在后面来了解如何在运行时来查询attributes)派生类中的help attribute,咱们将不可能查询到由于”Inherited”被设为了false。
第二种状况
第二种状况没有什么不一样,由于其”Inherited”也被设为了false。
第三种状况
为了解释第三种和第四种状况,让咱们为派生类也绑定同一attribute。
[Help("BaseClass")]
publicclass Base
{
}
[Help( "DeriveClass")]
publicclass Derive : Base
{
}
如今咱们查询相关的 help attribute ,咱们将仅仅能够获得派生类的attribute,为何这样是由于help attribute虽然容许被继承,但不能屡次在同一语言元素上使用,因此基类中的help attribute被派生类的help attribute 重写了。
第四种状况
在第四种状况中,当咱们查询派生类的help attribute 时,咱们能够获得两个attributes,固然是由于help attribute既容许被继承,又容许在同一语言元素上屡次使用的结果。
注意:AttributeUsageattribute 仅应用在那种是System.Attribute派生的attriubte类并且绑定值该attriubte类的AllowMultiple和Inherited均为false上才是有效的。
可选参数vs. 命名参数
可选参数是attribute类构造函数的参数。它们是强制的,必须在每次在attribute绑定至某语言元素时提供一个值。而另外一方面,命名参数却是真正的可选参数,不是在attribute构造函数的参数。
为了更加详细的解释,让咱们在Help类中添加另外的属性。
[AttributeUsage(AttributeTargets.Class, AllowMultiple =false,
Inherited =false)]
publicclass HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
this.verion ="No Version is defined for this class";
}
protected String description;
public String Description
{
get
{
returnthis.description;
}
}
protected String version;
public String Version
{
get
{
returnthis.version;
}
//if we EVE r want our attribute user to set this property,
//we must specify set method for it
set
{
this.verion = value;
}
}
}
[Help( "This is Class1")]
publicclass Class1
{
}
[Help( "This is Class2", Version ="1.0")]
publicclass Class2
{
}
[Help( "This is Class3", Version ="2.0",
Description ="This is do-nothing class")]
publicclass Class3
{
}
当咱们在 Class1中查询Help attribute已经它的属性,咱们将获得:
Help.Description : This is Class1
Help.Version :No Version is defined for this class
由于咱们没有为Version这个属性定义任何任何值,因此在构造函数中设定的值被咱们查询出来了。若是没有定义任何值,那么就会赋一个该类型的默认值(例如:若是是int型,默认值就是0)。
如今,查询Class2的结果是:
Help.Description : This is Class2
Help.Version : 1.0
咱们不能为了可选参数而使用多个构造函数,应该用已命名参数来代替。咱们之因此称它们为已命名的,是由于当咱们在构造函数为它们提供值时,咱们必须命名它们。例如,在第二个类中,咱们如是定义Help。
[Help("This is Class2", Version = "1.0")]
在AttributeUsage 例子中, 参数”ValidOn”是可选参数,而“Inherited“和“AllowMultiple“ 是命名参数。
注意:为了在attribute的构造函数中设定命名参数的值,咱们必须为相应的属性提供一个set方法不然会引发编译期错误:
'Version' : Named attribute argument can't be a read only property
如今,咱们在Class3中查找Help attribute 及其属性会发生什么呢?结果是跟上面提到的相同的编译期错误。
'Desciption' : Named attribute argument can't be a read only property
如今咱们修改下Help类,为属性”Description”加一个set方法。如今的输出就是:
Help.Description : This is do-nothing class
Help.Version : 2.0
在屏幕后面究竟发生了什么呢?首先带有可选参数的构造函数被调用,而后,每一个命名参数的set方法被调用,在构造函数中赋给命名参数的值被set方法所覆写。
参数类型
一个attribute类的参数类型被限定在以下类型中:
bool,
byte,
char,
double,
float,
int,
long,
short,
string
System.Type
object
An enum type, provided that it and any types in which it is nested are publicly accessible. A one-dimensional array involving any of the types listed above
Attributes 标记
假设,咱们想把Help attribute 绑定至元素assembly。第一个问题是咱们要把Help attribute 放在哪儿才能让编译器肯定该attribute是绑定至整个assembly呢?考虑另外一种状况,咱们想把attribute绑定至一个方法的返回类型上,怎样才能让编译器肯定咱们是把attribute绑定至方法的返回类型上,而不是整个方法呢?
为了解决诸如此类的含糊问题,咱们使用attribute标识符,有了它的帮助,咱们就能够确切地申明咱们把attribute 绑定至哪个语言元素。
例如:
[ assembly: Help("this a do-nothing assembly")]
这个在Help attribute 前的assembly标识符确切地告诉编译器,该attribute被绑定至整个assembly。可能的标识符有:
assembly
module
type
method
property
EVE nt
field
param
return
在运行时查询Attributes
如今咱们明白怎么建立attribtes和把它们绑定至语言元素。是时候来学习类的使用者该如何在运行时查询这信息。
为了查询一语言元素上绑定的attributes,咱们必须使用反射。反射有能力在运行时发现类型信息。
咱们可使用.NET Framework Reflection APIs 经过对整个assembly元数据的迭代,列举出assembly中全部已定义的类,类型,还有方法。
记住那旧的Helpattribute 和AnyClass类。
using System;
using System.Reflection;
using System.Diagnostics;
//attaching Help attribute to entire assembly
[assembly : Help( "This Assembly demonstrates custom attributes
creation and their run -time query.")]
//our custom attribute class
publicclass HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
//
// TODO: Add constructor logic here
this.description = Description_in;
//
}
protected String description;
public String Description
{
get
{
returnthis.deescription;
}
}
}
//attaching Help attribute to our AnyClass
[HelpString( "This is a do-nothing Class.")]
publicclass AnyClass
{
//attaching Help attribute to our AnyMethod
[Help( "This is a do-nothing Method.")]
publicvoid AnyMethod()
{
}
//attaching Help attribute to our AnyInt Field
[Help( "This is any Integer.")]
publicint AnyInt;
}
class QueryApp
{
publicstaticvoid Main()
{
}
}
咱们将在接下来的两节中在咱们的 Main方法中加入attribute查询代码。
查询程序集的Attributes
在接下来的代码中,咱们先获得当前的进程名称,而后用Assembly类中的LoadForm()方法加载程序集,再有用GetCustomAttributes()方法获得被绑定至当前程序集的自定义attributes,接下来用foreach语句遍历全部attributes并试图把每一个attribute转型为Help attribute(即将转型的对象使用as关键字有一个优势,就是当转型不合法时,咱们将不需担忧会抛出异常,代之以空值(null)做为结果),接下来的一行就是检查转型是否有效,及是否是为空,跟着就显示Help attribute的“Description”属性。
class QueryApp
{
publicstaticvoid Main()
{
HelpAttribute HelpAttr;
//Querying Assembly Attributes
String assemblyName;
Process p = Process.GetCurrentProcess();
assemblyName = p.ProcessName +".exe";
Assembly a = Assembly.LoadFrom(assemblyName);
foreach (Attribute attr in a.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null!= HelpAttr)
{
Console.WriteLine( "Description of {0}:\\n{1}",
assemblyName,HelpAttr.Description);
}
}
}
}
程序输出以下:
Description of QueryAttribute.exe:
This Assembly demonstrates custom attributes creation and
their run-time query.
Press any key to continue
查询类、方法、类成员的Attributes
下面的代码中,咱们唯一不熟悉的就是Main()方法中的第一行。
Type type = typeof(AnyClass);
它用typeof操做符获得了一个与咱们AnyClass类相关联的Type型对象。剩下的查询类attributes代码就与上面的例子是类似的,应该不要解释了吧(我是这么想的)。
为查询方法和类成员的attributes,首先咱们获得全部在类中存在的方法和成员,而后咱们查询与它们相关的全部attributes,这就跟咱们查询类attributes同样的方式。
class QueryApp
{
publicstaticvoid Main()
{
Type type =typeof(AnyClass);
HelpAttribute HelpAttr;
//Querying Class Attributes
foreach (Attribute attr in type.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null!= HelpAttr)
{
Console.WriteLine( "Description of AnyClass:\\n{0}",
HelpAttr.Description);
}
}
//Querying Class-Method Attributes
foreach(MethodInfo method in type.GetMethods())
{
foreach (Attribute attr in method.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null!= HelpAttr)
{
Console.WriteLine( "Description of {0}:\\n{1}",
method.Name,
HelpAttr.Description);
}
}
}
//Querying Class-Field (only public) Attributes
foreach(FieldInfo field in type.GetFields())
{
foreach (Attribute attr in field.GetCustomAttributes(true))
{
HelpAttr = attr as HelpAttribute;
if (null!= HelpAttr)
{
Console.WriteLine( "Description of {0}:\\n{1}",
field.Name,HelpAttr.Description);
}
}
}
}
}
The output of the following program is.
Description of AnyClass:
This is a do-nothing Class.
Description of AnyMethod:
This is a do-nothing Method.
Description of AnyInt:
This is any Integer.
Press any key to continue