一、自定义特性
特性是一种特殊的类。
要点:
- 用户自定义的特性类叫作自定义特性。
- 所有特性类都派生自 System.Attribute
1、声明自定义特性
声明:
public sealed class MyAttributeAttribute : System.Attribute
{
...
}
由于特性持有目标的信息,所有特性类的公有成员只能是:
- 字段
- 属性
- 构造函数
2、使用特性的构造函数
构造函数的显式隐式声明定义,以及重载等等,规则跟其他类一样。
public MyAtrributeAttribute(string desc, string ver)
{
...
}
3、指定构造函数
[MyAttribute("Holds a value")]//使用一个字符串的构造函数
public int MyField;
[MyAttribute("Version 1.3", "Galen Daniel")]//使用两个字符串的构造函数
public void MyMethod()
{
...
}
//MyAttribute:特性类
特性构造函数要点:
- 构造函数的实参必须是在编译时能确定值的常量表达式。
- 如果构造函数没有参数,代码如下:
[MyAttr]
class SomeClass...
[MyAttr()]
class OtherClass...
4、使用构造函数
//命令语句
MyClass mc = new MyClass("Hello", 5);
//声明语句
[MyAttribute("Holds a value")]
特性类和其他类,比较构造函数的使用:
- 命令语句的实际意义是:“在这里创建新的类。
- 声明语句的意义是:“这个特性和这个目标相关联,如果需要构造特性,则使用这个构造函数。”
5、构造函数中的位置参数和命名参数
[MyAttribute("An excellent class", Reviewer="Amy McArthur",Ver="0.7.15.33")]
//位置参数:An excellent class
//命名参数:Reviewer="Amy McArthur"、Ver="0.7.15.33"
示例:
public sealed class MyAttributeAttribute : System.Attribute
{
public string Description;
public string Ver;
public string Reviewer;public MyAttributeAttribute(string desc)//一个形参
{
Description = desc;
}
}[MyAtrribute("An excellent class", Reviewer="Amy McArthur", Ver="7.15.33")]
class MyClass
{
...
}
二、限制特性的使用
AttributeUsage 特性: 用来限制将特性用在某个目标类型上。
如果希望自定义特性 MyAttribute 只能应用到方法上。
[AttributeUsage(AttributeTarget.Method)]
public sealed class MyAtrributeAttribute : System.Attribute
{
...
}
表-AttributeUsage 的公有属性
名字 | 意义 | 默认值 |
---|---|---|
ValidOn | 保存能应用特性的目标类型的列表。构造函数的第一个参数必须是 AtrributeTargets 类型的枚举值 | |
Inherited | 一个布尔值,它指示特性是否可被装饰类型的派生类所继承 | true |
AllowMutiple | 一个布尔值,指示目标上是否可应用特性的多个实例的 | false |
1、AtrributeUsage 的构造函数
AtrributeUsage 的构造函数接受单个位置参数,该参数指定了可使用特性的目标类型。它用这个参数来设置 ValidOn 属性,可接受的目标类型是 AttributeTargets 枚举的成员。
可用通过使用按位或运算符来组合使用类型。
[AttributeUsage(AttributeTarget.Method | AtrributeTarget.Constructor)]
public sealed class MyAttributeAttribute : System.Attribute
{
...
}
AttributeTargets 枚举的成员
– | – | – | – |
---|---|---|---|
All | Assembly | Class | Constructor |
Delegate | Enum | Event | Field |
GenericParameter | Interface | Method | Module |
Parameter | Property | ReterunValue | Struct |
- MyAttribute 只能应用到类上。
- MyAttribute 不会被用用它的类的派生类所继承。
- 不能在同一个目标上应用 MyAttribute 的多个实例。
[AttributeUsage(AttributeTarget.Class,Inherited = false,AllowMultiple = false)]
public sealed class MyAttribute : System.Attribute
{
...
}
三、自定义特性的最佳实践
1、自定义特性实践
建议自定义特性时:
- 特性类应用表示目标结构的某种状态。
- 如果特性需要某些字段,可以通过包含具有位置参数的构造函数来收集数据,可选字段可以用采用命名参数按需初始化。
- 除了属性之外,不要实现公有方法或其他函数成员。
- 为了更安全,把特性类声明为 sealed。
- 在特性声明中使用 AttributeUsage 来显式指定特性目标组。
[AttributeUsage(AttributeTargets.Class)]
public sealed class ReviewCommentAtrribute : System.Attribute
{
public string Description {get; set;}
public string VersionNumber {get;set;}
public string ReviewrID {get;set;}public ReviewCommentAtrribute(string desc,string ver)
{
Description = desc;
VersionNumber = ver;
}
}
2、访问特性
使用 Type 对象来获取类型信息。Type 的两个方法:IsDefine 和 GetCustomAttributes。
1)使用 IsDefine 方法
可以使用 Type 对象 的 IsDefine 方法来检测某个特性是否应用到了某个类上。
[AttributeUsage(AttributeTargets.Class)]
public sealed class ReviewCommentAttribute : System.Attribute
{...}[ReviewComent("Check ite out","2.4")]
class MyClass{ }class Program
{
static void Main()
{
MyClass mc = new MyClass();
Type t = mc.GetType();
bool isDefined = t.IsDenfined(typeof(ReviewCommentAtrribute),false);if(isDefined)
{
Console.WriteLine($"ReviewComment is applied to type { t.Name }");
}
}
}
输出结果:
ReviewComment is applied tp type MyClass
2)使用 GetCustomAttributes 方法
Type 类的 GetCustomAttributes 方法返回用用到结构上的特性的数组。
- 实际返回的对象时 object 数组,因此我们必须将它强制转换为相应的特性类型。
- 布尔参数指定是否搜索继承树来查找特性。
object[] AttArr = t.GetCustomAttributes(false);
- 调用 GetCustonnAttributes 方法后,每一个与目标相关联的特性的实例就会被创建。
[AttributeUsage(AttributeTargets.Class)]public sealed class MyAtrributeAttribute : System.Attribute{public string Description { get; set; }public string VersionNumber { get; set; }public string ReviewerID { get; set; }public MyAtrributeAttribute(string desc, string ver){Description = desc;VersionNumber = ver;}}[MyAtrribute("Check it out","2.4")]class MyClass{ }class Program{static void Main(string[] args){Type t = typeof(MyClass);object[] AttArr = t.GetCustomAttributes(false);foreach(Attribute a in AttArr){MyAtrributeAttribute attr = a as MyAtrributeAttribute;if(null != attr){Console.WriteLine($"Decription : { attr.Description }");Console.WriteLine($"Version Number : { attr.VersionNumber }");Console.WriteLine($"Reviewer ID : { attr.ReviewerID }");}}Console.ReadKey();}}
输出结果:
Decription : Check it out
Version Number : 2.4
Reviewer ID :