[你必须知道的.NET] 第三回:历史纠葛:特性和属性
系列文章导航:
[你必须知道的.NET] 第四回:后来居上:class和struct
[你必须知道的.NET] 第五回:深入浅出关键字---把new说透
[你必须知道的.NET] 第六回:深入浅出关键字---base和this
[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始
[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边
[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途
[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)
[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)
[你必须知道的.NET] 第十三回:从Hello, world开始认识IL
[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在
[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触
[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考
[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二
4. 特性的应用
4.1. 常用特性
常用特性,也就是.NET已经提供的固有特性,事实上在.NET框架中已经提供了丰富的固有特性由我们发挥,以下精选出我认为最常用、最典型的固有特性做以简单讨论,当然这只是我的一家之言,亦不足道。我想了解特性,还是从这里做为起点,从.NET提供的经典开始,或许是一种求知的捷径,希望能给大家以启示。
• AttributeUsage
AttributeUsage特性用于控制如何应用自定义特性到目标元素。关于AttributeTargets、AllowMultiple、Inherited、ValidOn,请参阅示例说明和其他文档。我们已经做了相当的介绍和示例说明,我们还是在实践中自己体会更多吧。
• Flags
以Flags特性来将枚举数值看作位标记,而非单独的数值,例如:
Code
enum Animal
{
Dog = 0x0001,
Cat = 0x0002,
Duck = 0x0004,
Chicken = 0x0008
}
因此,以下实现就相当轻松,
Code
Animal animals = Animal.Dog | Animal.Cat;
Console.WriteLine(animals.ToString());
请猜测结果是什么,答案是:"Dog, Cat"。如果没有Flags特别,这里的结果将是"3"。关于位标记,也将在本系列的后续章回中有所交代,在此只做以探讨止步。
• DllImport
DllImport特性,可以让我们调用非托管代码,所以我们可以使用DllImport特性引入对Win32 API函数的调用,对于习惯了非托管代码的程序员来说,这一特性无疑是救命的稻草。
Code
• Serializable
Serializable特性表明了应用的元素可以被序列化(serializated),序列化和反序列化是另一个可以深入讨论的话题,在此我们只是提出概念,深入的研究有待以专门的主题来呈现,限于篇幅,此不赘述。
• Conditional
Conditional特性,用于条件编译,在调试时使用。注意:Conditional不可应用于数据成员和属性。
还有其他的重要特性,包括:Description、DefaultValue、Category、ReadOnly、BrowerAble等,有时间可以深入研究。
4.2. 自定义特性
既然attribute,本质上就是一个类,那么我们就可以自定义更特定的attribute来满足个性化要求,只要遵守上述的12条规则,实现一个自定义特性其实是很容易的,典型的实现方法为:
• 定义特性
Code
• 应用目标元素
Code
[Test("Error Here.")]
public void CannotRun()
{
//
}
• 获取元素附加信息
如果没有什么机制来在运行期来获取Attribute的附加信息,那么attribute就没有什么存在的意义。因此,.NET中以反射机制来实现在运行期获取attribute信息,实现方法如下:
Code
public static void Main()
{
Tester t = new Tester();
t.CannotRun();
Type tp = typeof(Tester);
MethodInfo mInfo = tp.GetMethod("CannotRun");
TestAttribute myAtt = (TestAttribute)Attribute.GetCustomAttribute(mInfo, typeof(TestAttribute));
myAtt.RunTest();
}