什么是特性,我自己的理解是:

特性是一种允许我们向程序集增加元数据的语言结构。它是用于保存程序结构信息的特殊的类。特性有2个基本概念:“目标”,“消费者”,就拿特殊性DebuggerStepThrough来说,编译器就是消费者,当它遇到被此特性注册过的Mothed时,就不会进入此Mothed执行(断点时)会直接得到此Methed的运行结果,而次Method就是目标了。总而言之,应用了特性的语言结构叫“目标”;设计用来获取和使用此特性的就叫“消费者”。

下面讲解.Net自带的几个比较著名的特性

1,Obsolete : 提示Method过时

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceAtrributeTest.com{///<summary>///用于测试Obsolete特性///目标:Method///消费者:IDE///</summary>publicsealedclassObsoleteTest{[Obsolete("这个方法已经过时,请使用MyNewMethod方法",false)]publicvoidMyOldMethd(){Console.WriteLine("这是一个过时的方法");}publicvoidMyNewMethod(){Console.WriteLine("这是一个新方法");}}}

测试:

可以看出当IDE跳出提示时,会自动在有“Obsolete”标志的Method上划一横线(表示不提倡使用),我在Obsolete的构造函数中提示“这个方法已经过时,请使用MyNewMethod方法”也只IDE提示中显示出来。关于Obsolete的第二个参数(Boolean),它表是“是否不能使用”。如果为true,当使用了MyOldMethd方法后,编译会报错;反之(False的情况),只是不提倡使用。


2,Conditional : 取消Method的任何调用

这个的话我认为并没有编译参数好用。我先放测试代码,再给出解释

1,此内中有一个方法“MyTestMethod”被Conditional特性修饰

usingSystem;usingSystem.Collections.Generic;usingSystem.Diagnostics;usingSystem.Linq;usingSystem.Text;namespaceAtrributeTest.com{///<summary>///用于测试Condition特性///目标:Method///消费者:IDE(将影响编译)///</summary>publicsealedclassConditionalTest{[Conditional("IsTest")]publicvoidMyTestMethod(){Console.WriteLine("这是我的测试方法,请在正式上线后注释掉");}}}

此方法在2处调用

①:

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceAtrributeTest.com{///<summary>///用于测试Obsolete特性///目标:Method///消费者:IDE///</summary>publicsealedclassObsoleteTest{[Obsolete("这个方法已经过时,请使用MyNewMethod方法",false)]publicvoidMyOldMethd(){Console.WriteLine("这是一个过时的方法");}publicvoidMyNewMethod(){Console.WriteLine("这是一个新方法");ConditionalTestcontTest=newConditionalTest();contTest.MyTestMethod();}}}

②:Main函数

#defineIsTestusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingAtrributeTest.com;namespaceAtrributeTest{publicclassProgram{staticvoidMain(string[]args){Console.WriteLine("ObsoleteTest..........................");ObsoleteTestobsTest=newObsoleteTest();obsTest.MyNewMethod();Console.WriteLine("Program..........................");ConditionalTestconTest=newConditionalTest();conTest.MyTestMethod();Console.ReadKey();}}}

在Program中我定义了一个宏 IsTest , 所以在此类的Main函数中MyTestMethod是可以被执行的。但是在ObsoleteTest内中没有定义此宏,所以此类的方法MyNewMethod中的MyTestMethod是不会被执行的。这点值得注意。实际上在IDE中已经给予了提示:

在注册过IsTest宏的Program类,如下图:

在没有注册过宏IsTest宏的ObsoleteTest类,如下图:

值得注意注意的是 ,① 宏一定要放在所有using的前面 ; ②宏的定义要与[Conditional("IsTest")]后面的参数一样,但是不能要“”(引号)

但是如果整个项目的此Method都能/不能调用 , 单单一个个在Class中加/删宏会累死你的 。这里本人有个好方法“预处理指令”在本人的博客《C#的预处理指令的全局设计》中有,但是还有一个此特性还有一个缺点:

所有引用(调用)此Method的地方不会被编译,但是定义它的地方会被编译。建议还是使用#if / #endif


自定义特性:(要注意三点)

一:需要继承Attribute类

二:需要以Attribute单词作为后缀名

三:最好申明为sealed,需要申明此特性的消费着

好,现在来整一个Demo,现在一步步实现

①建立第一个自定义特性,如下图

②完整代码:

usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;namespaceAtrributeTest.com{///<summary>///自定义一个特性///</summary>[AttributeUsage(AttributeTargets.Class)]//表示此特性可以应用到那些程序结构publicsealedclassMyTestAttribute:Attribute{privatestringdes;publicintId{get;set;}publicMyTestAttribute(string@des){this.des=des;}}}

③使用自定义特性

注意 : 使用反射获取特性信息

usingSystem;usingAtrributeTest.com;namespaceAtrributeTest{[MyTest("我的第一个特性",Id=1)]publicclassProgram{privatestaticvoidMain(string[]args){Type@ty=typeof(Program);object[]arr=ty.GetCustomAttributes(false);//是否搜索父类上的特性MyTestAttributemy=arr[0]asMyTestAttribute;Console.WriteLine("特性类的des:{0}",my.des);Console.WriteLine("特性类的ID号:{0}",my.Id);Console.ReadKey();}}}