Attribute(特性):是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。
Attribute的名称和值是在方括号"[ ]"内规定的,放置在它所应用的元素之前。
Attribute会在编译时写入到元数据中。
目前的理解是:我们可以在运行时通过检索Attribute来筛选得到特定的元素。
注:所有继承自Attribute的类可以省略后面的Attribute字段。如:
public sealed class AttributeUsageAttribute : Attribute
使用时简写为[AttributeUsage(...)]
一、预定义特性
.Net框架提供了3种预定义特性:
1.AttributeUsage
一般来讲,AttributeUsage是为了描述自定义特性,规定了特性可应用到的项目类型。
AttributeUsage的构造接受三个类型的参数:
[AttributeUsage(
validon,
AllowMultiple=allowmultiple,
Inherited=inherited
)]
validon:此位置参数指定可以置于所指示的特性的程序元素。 中列出的一套可将属性置于的所有可能元素AttributeTargets枚举。 可以将一些组合AttributeTargets使用位或运算,以获取有效的程序元素的所需的组合值。
AllowMultiple:此命名的参数指定是否可以为给定的程序元素多次指定指示的属性。
Inherited:此命名的参数指定是否可以由派生的类和重写成员继承所指示的属性。
例如:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
2.Conditional
这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符。
语法如下:
[Conditional(
conditionalSymbol
)]
这个特性一般用作调试。
例:
#define DEBUG
//#define NODEBUG
public class A{
Conditional("NODEBUG")
public void Func1(){
...
}
[Conditional("DEBUG")]
public void Func2(){
...
}
}
A中的Func1和Func2,只有Func1会被调用。
3.Obsolete
这个预定义特性标记了不应被使用的程序实体。它可以让你通知编译器丢弃某个特定的目标元素。
例如,当一个新方法被用在一个类中,但是仍然想要保持类中的旧方法,可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。
[Obsolete(
message
)]
[Obsolete(
message,
iserror
)]
message:描述项目为什么过时的原因以及该替代使用什么。
iserror:如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。
二、自定义特性
创建并使用自定义特性包含四个步骤:
- 声明自定义特性
- 构建自定义特性
- 在目标程序元素上应用自定义特性
- 通过反射访问特性
贴一个官方的例子:
using System;
using System.Reflection;
//用枚举来表示类型
public enum Animal {
Dog = 1,
Cat,
Bird,
}
//自定义特性,可以用AttributeUsage特性来描述
public class AnimalTypeAttribute : Attribute {
//提供构造。
//特性实现的本质其实是为要描述的元素创建一个特性实例。
public AnimalTypeAttribute(Animal pet) {
thePet = pet;
}
protected Animal thePet;
public Animal Pet {
get { return thePet; }
set { thePet = value; }
}
}
//里面的三个方法分别用AnimalType特性描述
class AnimalTypeTestClass {
[AnimalType(Animal.Dog)]
public void DogMethod() {}
[AnimalType(Animal.Cat)]
public void CatMethod() {}
[AnimalType(Animal.Bird)]
public void BirdMethod() {}
}
class DemoClass {
static void Main(string[] args)
{
//取得测试实例
AnimalTypeTestClass testClass = new AnimalTypeTestClass();
Type type = testClass.GetType();
//通过特性检索取得对应的方法
foreach(MethodInfo mInfo in type.GetMethods())
{
foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo))
{
if (attr.GetType() == typeof(AnimalTypeAttribute))
Console.WriteLine(
"Method {0} has a pet {1} attribute.",
mInfo.Name, ((AnimalTypeAttribute)attr).Pet);
}
}
}
}
输出:
Method BirdMethod has a pet Bird attribute
Method CatMethod has a pet Cat attribute
Method BirdMethod has a pet Bird attribute
我们通过给元素“打标签”,达到了检索的目的。
Attribute给我们提供了和元数据更密切的“交流”。