这是一篇C#特性的学习记录。
特性,我暂时的理解就是给给C#中的一些类如方法、类等等元素添加一些额外的信息。这些信息由不同的特性定义。一会会举例子说明。而C#中的特性分为预定义特性和自定义特性。今天简单的记录几个。
特性的总体设置语法如下:
[特性名(特性内容)]
这个特性内容根据不同的特性有不同的写法。
①预定义特性
预定义特性这里介绍两种
1.Obsolete
2.Conditional
先看看Obsolete,这个特性的语法如下:
[Obsolete(信息)]或[Obsolete(信息,true/false)]
这个特性具体的功能我觉得就是给使用这个特性的元素添加一些过时后是否可用的信息,这个信息包括能不能用,显示什么过时信息两部分。下面看个例子:
上面的代码可以看出,将obsolete特性应用到方法上,执行这个方法时,会看到该特性的定义内容。首先是第一个参数“用不成了”,当你把鼠标放在使用这个方法的地方,就会显示这条信息,第二个参数“true”,这个参数表示这个方法还能不能用,true就是用不成了,会直接报错,false就是还能用,但也会报警告。如果不写第二个参数,应该是默认false的。
再来看看Conditional,这个是要配合预定义指令一起用的。
这个就是根据预处理指令#define定义的内容,来决定使用该特性的元素是否参与编译。格式如下:
[Conditional("DEBUG")]或[Conditional("Trace")]
上面这两种定义我觉得使用起来是一样的,但DEBUG主要可能用于调试时输出,Trace主要用于信息追踪。即用是一样的用,但不同的功能自己按不同的写法来进行区分。
下面举个例子:这个例子没有用到调试和追踪,只是简单的展示一下
在代码最上面记得添加以下代码:
#define DEBUG
看上面的代码,DEBUG是通过#define定义过的,所以print1是可以用的,但Trace没定义,所以最终打印结果应该只有print1打印的内容。
结果:
仅一个123。
至于#define的用法,这个一般是和其他预处理指令一起用的,比如
#if
#else
#endif
举个例子:
在前一个例子中加入上图的内容,因为定义了DEBUG,所以456就会打印到控制台,789就不会。
②自定义特性
最后再看以下自定义特性,该特性的声明需要用到AttributeUsage。语法如下:
[AttributeUsage(AttributeTargets.Class |AttributeTargets.Constructor |AttributeTargets.Field |AttributeTargets.Method |AttributeTargets.Property,AllowMultiple = true)]
public class DeBugInfo : System.Attribute
咱一步一步看,首先AttributeUsage,这个就是该特性的名字了,后面的内容都写在括号里了。AttributeTargets:这个表示该特性可以用于哪些元素,比方说AttributeTargets.Class就表示这个特性可以用于类,后面的依次类推。后面的AllowMultiple是AttributeUsage类的一个属性,选择true就是说允许在同一个目标上多次应用这个自定义属性。最下面一行表示该类继承自System.Attribute,这是每个自定义特性必须的。而且每个自定义特性都必须有构造函数,最少一个。下面来看一个例子:
先来定义一个特性:
上面的特性首先继承自System.Attribute,AttributeTargets.Method|AttributeTargets.Property表示该特性可以应用在方法和属性上。然后下方是一些定义的属性,这些属性会在构造函数中进行使用,可以看到下方的构造函数中就是对姓名和年龄进行赋值。最后一个分数在构造函数中没用使用,这就为该特性在定义时提供了可选择的输入内容,等下的例子中就可以看出这点。
这个类就应用到了刚才定义的MESSAGE特性,在定义该特性时,首先需要遵从特性的同一语法,就是文章开头写的那个,其次就是要遵从该特性的构造函数了。比如该特性的构造函数中包括两个参数,那在使用该特性时,这两个参数一定要加到括号里,但_score没用在构造函数里,所以可以选择性加入,上面都有举例。
然后最后说一下这个有什么用哈,上面定义的特性其实就是给这些个属性方法添加一些标签,这些内容可以协同反射的内容进行搜索,这个就需要写到反射的时候再说了,我这暂时还没咋看,所以也稀里糊涂的。