特性⚓︎
一、特性概述⚓︎
特性(Attribute)是一种用于在程序运行时传递各种元素(例如类、方法、结构、枚举等)行为信息的声明性代码。使用特性可以将元数据(例如编译器指令、注释、描述、方法和类等信息)添加到程序中。
在 C# 中,特性具有以下属性:
- 使用特性可以向程序中添加元数据,元数据是指程序中各种元素的相关信息,所有 .NET 程序中都包含一组指定的元数据;
- 可以将一个或多个特性应用于整个程序、模块或者较小的程序元素(例如类和属性)中;
- 特性可以像方法和属性一样接受自变量;
- 程序可使用反射来检查自己的元数据或其他程序中的元数据。
.Net 提供了两种类型的特性,分别是预定义特性和自定义特性。
- 预定义特性
AttributeUsage
:用于自定义特性,其中定义了可以应用特性的项目类型;Conditional
:用来标记一个方法,它的执行依赖于指定的预处理标识符;Obsolete
:用来标记废弃的程序,可以使用它来通知编译器放弃某个目标元素。
- 自定义特性
- 按规则和需要使用
AttributeUsage
实现特性自定义。
- 按规则和需要使用
Tip
如果你熟知 Java 语言,你可以认为它和 Java 中的元注解具有相同的功能。
二、预定义特性⚓︎
01 AttributeUsage⚓︎
使用 AttributeUsage
可以实现自定义特性,它的语法格式如下:
参数说明:
AttributeTargets
:用于指定自定义的特性应用的目标位置,AttributeTargets.ALL 表示对程序中的所有成员都可用,Class 表示应用于类,Method 表示应用于方法,Constructor 表示应用于构造器,Field 表示应用于字段,Property 表示应用于属性。可以同时指定多个 AttributeTargets,此时,应该使用符号|
分隔开。Inherited
:用于指定自定义的特性是否可以被派生类继承,取值为 true (默认)或 false。AllowMultiple
:用于指定一个元素是否可以被标记多个自定义特性的实例,取值为 true 或 false(默认)。
02 Conditional⚓︎
使用 Conditional
用来标记一个方法,它的执行依赖于指定的预处理标识符。例如当值为 Debug 或 Trace 时,会在调试代码时显示变量的值。它的语法格式如下:
示例:
03 Obsolete⚓︎
使用 Obsolete
用来标记程序段被弃用,例如当您需要使用一个新方法来替代类中的某个旧方法时,就可以使用该特性将旧方法标记为 obsolete(过时的)并来输出一条消息,来提示应该使用新方法代替旧方法。它的语法格式如下:
参数说明:
Message
:描述性字符串,可以用来说明弃用以及原因。IsError
:用来标识使用弃用的方法是一个错误,取值为 true 或 false (默认)。当为 true 时,若代码段被调用程序将会报错。UrlFormat
:用于指定一个 URL ,可以是一个说明文档的链接。
示例:
[Obsolete("方法已弃用",true)]
public static void Test(){}
private static void Main(string[] args)
{
Test(); // 编译器会发出提醒,强行运行会报错
}
三、自定义特性⚓︎
通过 AttributeUsage
可以实现自定义特性,自定义特性和自定义类一样简单,自定义特性就是一个传统类,这些类直接或间接派生自 System.Attribute
类,与传统类一样,包含存储和检索数据的方法。
自定义一个特性的步骤可以参考: 1. 声明自定义特性; 2. 构建自定义特性; 3. 在目标程序上应用自定义特性; 4. 通过反射访问特性。
Note
- 特性类必须声明为公共类。
- 按照约定,属性类的名称以单词 Attribute 结尾。虽然不是必需的,但为了可读性,建议使用此约定。
- 所有属性类必须直接或间接地继承
System.Attribute
类。
示例:
[AttributeUsage(AttributeTargets.All)]
public class DeveloperAttribute : Attribute
{
// Private fields.
private string name;
private string level;
private bool reviewed;
// This constructor defines two required parameters: name and level.
public DeveloperAttribute(string name, string level)
{
this.name = name;
this.level = level;
this.reviewed = false;
}
// Define Name property.
// This is a read-only attribute.
public virtual string Name
{
get {return name;}
}
// Define Level property.
// This is a read-only attribute.
public virtual string Level
{
get {return level;}
}
// Define Reviewed property.
// This is a read/write attribute.
public virtual bool Reviewed
{
get {return reviewed;}
set {reviewed = value;}
}
}
然后就可以使用该属性了: