我们初学C#的时候看到类上面一对中括号里面有个高亮了的关键字,不知道那是什么有什么用。想问人又不知道它叫什么。纠结的要命。其实,它就是特性。如:
这就是我们今天要分析的主题。
特性是什么?个人理解,特性就是修饰对象元数据的修饰符。
那么什么是“元数据”?元数据就是用来描述数据的数据。(挺拗口的)
如:
图中的1.是特性 2.是访问修饰符 3.声明修饰符 4.数据类型 5.变量名 6.变量数据值,其中1、2、3、4、5就是元数据,用来描述数据(6)的数据。
特性到底是什么?如上面的 Obsolete ,会不会也是一个如 public static 这样类似的修饰符呢,我们且看看反编译后的中间语言。
意料之外,我们看到了上面的2、3、4、5,而1(特性)怎么跑到里面去了,且是一种看不懂的东东,反正我们知道了不是类似的修饰符。
然后我们接着在vs里面把光标移到 Obsolete 上按F12,如:
原来只是一个继承了 Attrbute 的一个类(class)。那么上面我们看不懂的部分应该就是这个 ObsoleteAttribute 类的实例化了。
我们来回答上面问题:特性到底是什么?特性只是一个类而已。
我们自定义一个特性玩玩我们看到上面系统特性 Obsolete 上面还有特性,如:Serializable、AttributeUsage、Camvisible等。像这种特性我们称之为“元数据的元数据”(元元数据)。
1.我们分别来解释性上面的三个特性。
Serializable:表示类型支持序列化。
ComVisible:微软定义“控制程序集中个别托管类型、 成员或所有类型对COM的可访问性”。
AttributeUsage:这个比较重要了,基本上每个特性定义都用到了它。它就是用来表示当前这个特性可用于哪些对象。如:类、方法、属性...等等。(只需要用到这个我们就可以自定义特性了)
2.上面有个问题,不知道大家发现没有。
就是我们特性名明明是 Obsolete ,为什么我们F12进去后变成了 ObsoleteAttribute 呢?这其实只是一个微软的约定而已,没有为什么。
其实我们可以两种写法: )] 和 )] 是等效的,只是我们一般都用后面这种。
3.定义的特性必须继承于 Attribute 。
4.属性没有set方法。只能通过构造函数赋值。(这是因为特性语法所致,因为特性的定义只存在单行的中括号中,不能实例化之后在设置属性,所以全部的设置都在后面的小括号里进行的)
好了,我们通过这四点完全可以自己定义个特性来玩玩了。我们来定义一个给机器看的注释。我们平时的注释都只是给程序员看的,编译之后就全没了。那我们想在代码运行时,弹出我们的注释怎么办,接下来我们用自定义特性来实现,如:
[AttributeUsage(AttributeTargets.All)]TMessgAttribute : Attribute//1.定义类TMessg加上后缀TMessgAttribute 2.继承Attribute。 { public TMessgAttribute() { } TMessgAttribute(string createTime, string createName, string mess) { this._createName = createName; this._createTime = createTime; this._mess = mess; } private string _createTime; public string createTime { get { return _createTime; }//4.只能有get方法 } private string _createName; public string createName { get { return _createName; } } private string _mess; public string mess { get { return _mess; } } }
好了,上面就是我们自定义的特性。那我们怎样使用呢。和系统特性一样。我们先定义一个测试类TClass,然后在类上面定义特性,如:
[TMessg(, , )] public class TClass { //................ }
我们定义了特性,也使用了特性,然我们却不知道怎么看效果。我们想看到效果怎么办。可以使用反射(下篇博问继续分析反射)看看 TClass 类的元数据,如:
static void Main(string[] args) { System.Reflection.MemberInfo info = typeof(TClass); //通过反射得到TClass类的信息 TMessgAttribute hobbyAttr = (TMessgAttribute)Attribute.GetCustomAttribute(info, typeof(TMessgAttribute)); Console.WriteLine(, info.Name); Console.WriteLine(, hobbyAttr.createTime); Console.WriteLine(, hobbyAttr.createName); Console.WriteLine(, hobbyAttr.mess); Console.ReadKey(); }
打印效果如:
什么是命名参数?