参考:https://www.w3cschool.cn/csharp/csharp-attribute.html
理解:
特性就是一个标签,可以给程序中的元素添加一些信息,在程序运行时就可以访问元素的这些信息,程序就可以通过这些信息进行其他操作。当然特性在编译期就存在了,所有编译器也可以通过这些特性信息进行条件编译。
1、定义:
(1) Attribute是用于 在编译或运行时 传递元素(如类、方法等)信息 的声明性标签。
(2) 是一个标签,用于传递元素的信息。
(3) 在编译期或运行期起作用。
(4) 元素:类、方法、属性、字段、结构、枚举、组件等。
2、内容:
(1) 通过放置在它所应用的元素前面的方括号([ ])来描述的。
(2) 特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。
(3) .Net 框架提供了两种类型的特性:预定义特性和自定义特性。
3、语法:
(1) 语法规则:
[attribute(positional_parameters, name_parameter = value, ...)]
element
(2) 特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。
positional_parameters 规定必需的信息;
name_parameter 规定可选的信息。
4、预定义特性:
.Net 框架提供了三种预定义特性:AttributeUsage、Conditional、Obsolete。
(1) AttributeUsage
01. 描述了如何使用一个自定义特性类。它规定了特性应用范围。
02. 理解:仅当自定义特性类时使用,放在类声明前,规定自定义特性类的使用范围、能否多用和能否被继承。
03. 语法:
[AttributeUsage(validOn, AllowMultiple = allowMultiple, Inherited = inherited)]
参数:
validOn 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
allowMultiple(可选的),如果为 true,则该特性是多用的(即该特性可以使用多次)。默认值是 false(单用的)。
inherited(可选的),如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
04. 例如:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
(2) Conditional
01. 标记方法为条件方法,表示方法的执行依赖于指定的预处理标识符。也就是条件编译,编译期起作用。
02. 原理:当运行到一个条件方法调用时,是否执行该调用,要根据出现该调用时是否已定义了此符号来确定。如果定义了此符号,则执行该调用;否则省略该调用(包括对调用的参数的计算)。
03. 用来代替#if,#endif,简洁不易出错。
04. 局限:Conditional只能用在整个方法上,因为可能要跳过执行,所以条件方法必须是可忽略的。有如下限制:
1. 条件方法的返回类型必须是void,参数不能有out(只有这样方法调用才能跳过)。
2. 条件方法必须是类或结构声明中的方法,不能是接口中的方法。
3. 不能用override修饰条件方法。
05. 语法如下:
[Conditional(conditionalSymbol)]
// 例如
[Conditional("DEBUG")] // 只在DEBUG下编译执行,Release下不编译不执行
[Conditional("TRACE")] // 在DEBUG、Release都编译执行
(3) Obsolete
01. 标记不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保留类中的旧方法的代码,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的,废弃的)。
02. 语法如下:
[Obsolete(message)]
[Obsolete(message, iserror)]
参数:message,描述具体信息,如该元素的废弃原因和代替方法。
Iserror,如果该值为true,编译器则把该元素的使用当作一个错误。默认值是 false(编译器则只会生成一个警告)。
5、自定义特性:
(1) 特性也是一个类,可以创建自定义特性类,用来给元素添加信息,在运行中可以被访问。
(2) 所有特性类都派生自标准库提供的 Attribute 基类。
(2) 创建和使用的步骤:
01. 声明:声明自定义特性;
02. 定义:构建自定义特性;
03. 应用:在目标程序元素上应用特性;
04. 访问:通过反射Reflection访问特性。
(3) 声明:
声明自定义特性类:要使用AttributeUsage标记,并继承System.Attribute 类。
(4) 定义:
定义特性类的具体内容,存储特性的具体内容。
每个特性必须至少有一个构造函数。必需的定位参数(positional)应通过构造函数传递。
(5) 访问:
01. 使用反射Reflection来访问特性attribute的信息。(Reflection是命名空间)
02. 例如:
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++)
{
System.Console.WriteLine(attributes[i]);
}
(6) 特殊运用:如果特性的名称以 Attribute 结尾,那么可以在引用特性时省略这部分名称。
例如,可按如下方法使用 HelpAttribute。
[Help("xxx")]
public class Widget
{
[Help("xxx", Topic = "xxx")]
public void Display(string text)
{
}
}