这里之所以允许将位置型参数应用到f方法上,是因为该特性类型有个兼容的构造函数方法,它能接收一个单独的字符串参数。此外,允许命名参数的原因是该特性有相同名字的公有字段或属性。
传递给自定义特性的参数被序列化到元数据中,用于编译器发射该模块时的特性。为了允许参数值在运行时通过反射还原,自定义特性往往将其参数存储为实例字段,用于后期检有。如果要读取这些字段,则必须使用IcustomAttributeProvider.GetCustomAttributes方法获取内存中特性对象的引用。
GetCustomeAttributes方法返回一个特性对象的数组,并可以通过它查询特性的字段和属性。调用GetCustomerAttributes方法将导致序列化特性构造函数的执行。这样,在你的代码看到这些特性对象之前,它们就已经在元数据中被实例化了。
GetCustomAttributes方法能够被重载,使得它接收一个可选的System.Type对象,标明需什么类型的特性。如果没有指定System.Type.那么.GetCustomAttributes将返回与类型无关的所有自定义特性。无论哪种情况,这个方法都会返回一个(潜在为空)System.Object引用的数组:
示例4.3 中的例程演小r如何在运行时检查自定义特性的参数。这个示例访问了属于每个方法的DocumentedAttribute对象,并且显示该特性的不同字段。
示例4.3检查自定义特性的参数
最后,我们往往需要限制何处以及怎样应用自定义特性。为了允许自定义特性类型控制其用法,CLR定义了 System.AttributeUsageAttribute特性。这个特性可以被应用到自定义特性的类型定义,并且支持三个属性Validon属性标明特性可以被应用到哪种构件(例如,宇段、方法):
Inherited属性标明特性的存在是否应该对派生类型可见;
AllowMultiple属性标明是否可以对同一个目标应用多次特性,对于简单特性来说,这种用法没有意义。对于列表或集台上的自定义特性(考虑安全角色)来说,AllowMultipleatrue允许你对于列表的每个成员应月用一次特性。
考虑在整个讨论中采用的DocumentedAttribute类型的最后一个变体:
Using System;
{
AttributeUsage(AttributeTargets.Method,
Inherited=false,
AllowMultiple=true)
}
Public sealed class DocumentedAttribute:System.Attribute
{
Public DocumentedAttribute(){}
Public DocumentedAttribute(string w){Writer=w;}
Public string Writer;
Public int WordCount;
Public bool Reviewed;
}
这个新定义标明你只能对方法应用DocumentedAttribute特性。而且任何试图将该特性应用到字段或类型上都将导致失败。allowMultiple参数为true时意味着它允许下面的用法:
Public sealed class MyCode
{
[Documented(“Don Box”,WordCount=193)]
[Documented(“Chris Sells”,WordCount=1722)]
[Documented(“John Smith”,Reviewed=true)]
Static void f(){}
}
在这个用法中.f方法将会应用特性的三个实例。当你在相应的MetthodInfo对象上调用GetCustomAttributes方法时,其结果数组将包含三个兀素,且每个特性声明对应一个。
我们走到哪儿了类型在CLR元数据中是流通的基本单元。与传统c++类型和VisualBasic类型不同的是,CLR类型对于运行的程序是可见的,并且是所自基于CLR的程序在运行时执行的主要部分,类型定义很容易以编程的方式发射和读取;此外,你还可以使用自定义特性,以一种清晰的、强类型的方式扩展用于类型定义的元数据的格式。自定义特性的广泛应用所带来的可扩展性和可表达性,被有些人誉为CLR最深刻的特征,著名的COM专家CharlieKindel告诉我们:自定义特性比你想像的更强大。歔IN剉D