1.什么是Attribute?
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。
特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
规定特性(Attribute)
规定特性(Attribute)的语法如下:
[attribute(positional_parameters, name_parameter = value, ...)]
element
例如:
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class EnumAttribute : Attribute{
}
指定了特性可以使用到字段,一个字段上可以使用1个特性,不能使用多个,可以被继承
特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。
预定义特性(Attribute)
.Net 框架提供了三种预定义特性:
- AttributeUsage
- Conditional
- Obsolete
AttributeUsage
预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。
规定该特性的语法如下:
[AttributeUsage(
validon,
AllowMultiple=allowmultiple,
Inherited=inherited
)]
其中:
- 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
- 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
- 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
例如:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
Conditional
这个预定义特性标记了一个条件方法,其执行依赖于它顶的预处理标识符。
它会引起方法调用的条件编译,取决于指定的值,比如 Debug 或 Trace。例如,当调试代码时显示变量的值。
规定该特性的语法如下:
[Conditional(conditionalSymbol)]
例如:
[Conditional("DEBUG")]
public static void Message(string msg)
{
Console.WriteLine(msg);
}
Obsolete
这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)
规定该特性的语法如下:
[Obsolete(message)]
[Obsolete(message, iserror)]
其中:
- 参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么。
- 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。
下面的实例演示了该特性:
using System;
public class MyClass
{
[Obsolete("Don't use OldMethod, use NewMethod instead", true)]
static void OldMethod()
{
Console.WriteLine("It is the old method");
}
static void NewMethod()
{
Console.WriteLine("It is the new method");
}
public static void Main()
{
OldMethod();
}
}
当您尝试编译该程序时,编译器会给出一个错误消息说明:
Don't use OldMethod, use NewMethod instead
创建自定义特性(Attribute)
特性也是一个类,必须继承于System.Attribute类,命名规范为“类名”+Attribute。不管是直接还是间接继承,都会成为一个特性类,特性类的声明定义了一种可以放置在声明之上新的特性。
每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递
下面是一些开发自定义Attribute时,可能需要用到的资料:
【1】Attribute可以关联的元素包括:
程序集(assembly)、模块(module)、类型(type)、属性(property)、事件(event)、字段(field)、方法(method)、参数(param)、返回值(return)。
【2】AttributeTargets目标包括
标记 | 说明 |
All | 可以对任何应用程序元素应用属性。 |
Assembly | 可以对程序集应用属性。 |
Class | 可以对类应用属性。 |
Constructor | 可以对构造函数应用属性。 |
Delegate | 可以对委托应用属性。 |
Enum | 可以对枚举应用属性。 |
Event | 可以对事件应用属性。 |
Field | 可以对字段应用属性。 |
GenericParameter | 可以对泛型参数应用属性。 |
Interface | 可以对接口应用属性。 |
Method | 可以对方法应用属性。 |
Module | Module 指的是可移植的可执行文件(.dll 或 .exe),而非 Visual Basic 标准模块。 |
Parameter | 可以对参数应用属性。 |
Property | 可以对属性 (Property) 应用属性 (Attribute)。 |
ReturnValue | 可以对返回值应用属性。 |
Struct | 可以对结构应用属性,即值类型。 |
【3】AttributeUsageAttribute中的3个属性(Property)说明:
属性名 | 说明 |
该定位参数指定可在其上放置所指示的属性 (Attribute) 的程序元素。AttributeTargets 枚举数中列出了可在其上放置属性 (Attribute) 的所有可能元素的集合。可通过按位“或”运算组合多个 AttributeTargets 值,以获取所需的有效程序元素组合。 | |
该命名参数指定能否为给定的程序元素多次指定所指示的属性。 | |
该命名参数指定所指示的属性能否由派生类和重写成员继承。 |
一个特性应用实例
/// <summary>
///描述枚举的属性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class EnumAttribute : Attribute
{
private string _name;
private string _description;
/// <summary>
/// 枚举名称
/// </summary>
public string Name
{
get { return _name; }
set { _name = value; }
}
/// <summary>
/// 枚举描述
/// </summary>
public string Description
{
get { return _description; }
set { _description = value; }
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name">枚举名称</param>
public EnumAttribute(string name)
{
this.Name = name;
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="name">枚举名称</param>
/// <param name="description">枚举描述</param>
public EnumAttribute(string name, string description)
{
this.Name = name;
this.Description = description;
}
}
这是一个用于Enum类型字段上的Attribute
/// <summary>
/// 用于缓存枚举值的属性值
/// </summary>
private static readonly Dictionary<object, EnumAttribute> enumAttr = new Dictionary<object, EnumAttribute>();
/// <summary>
/// 获取枚举值定义的属性
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static EnumAttribute GetAttribute(Enum value)
{
if (enumAttr.ContainsKey(value))
{
EnumAttribute ea = enumAttr[value];
return ea;
}
else
{
FieldInfo field = value.GetType().GetField(value.ToString());
if (field == null) return null;
EnumAttribute ea = null;
object[] attributes = field.GetCustomAttributes(typeof(EnumAttribute), true);
if (attributes != null && attributes.Length > 0)
{
ea = (EnumAttribute)attributes[0];
}
enumAttr[value] = ea;
return ea;
}
}
使用特性,获取枚举值的描述
public enum MsgType
{
[Enum("文本")]
text,
news,
video,
images,
muiyc
}
GetDescription(MsgType.text);