1、官方概述
并发
特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集、类型、方法、属性等)相关联。 特性与程序实体关联后,便可在运行时使用名ide
为“反射”的技术查询特性。函数
特性,如Serializable,它其实就是一个类,定义方式跟类同样,且全部特性都是直接或间接继承自Attribute基类。对象
2、自定义一个特性blog
自定义一个特性PermissionAttribute:继承
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class PermissionAttribute : Attribute //类名是特性的名称 { public string compNo; //命名参数 private string _popeId, _popeName; public PermissionAttribute(string popeId,string popeName) //popeId、popeName为定位参数 { compNo = "DB_TEST"; _popeId = popeId; _popeName = popeName; } }
下面让咱们看看,如何建立一个自定义特性?ip
1)一个自定义特性类必须直接或间接继承自System.Attribute特性类。get
2)为该自定义特性类指定System.AttributeUsage特性,并指定限制参数(枚举System.AttributeTargets和可选的AllowMultiple、Inherited命名参数)。编译器
AttributeUsage的命名参数:AllowMultiple表示是否容许屡次使用在同一目标上、Inherited表示是否同时应用于派生类型或重载版本。string
3)类名是特性的名称。
4)构造函数的参数是自定义特性的定位参数(应用该特性时必须放在参数列表的最前面),也能够是无参构造函数(如[Serializable])。
5)任何公共的读写字段或属性都是可选的命名参数。
6)若是特性类包含一个属性,则该属性必须为读写属性。
3、应用特性
示例代码以下:
[Permission("01_01","用户资料",compNo ="DB_SYSTEM")] public class Users { public Users() { } public int AddUser(string userId,string userName) { return 1; } }
应用特性 [Permission("01_01","用户资料",compNo ="DB_SYSTEM")] 实际上是经过构造函数的调用来实例化一个特性类。
根据约定,全部特性名称都以单词“Attribute”结束,如可系列化标记特性Serializable,它的全称为SerializableAttribute。在代码中使用特性时,不须要
指定Attribute后缀,如上面代码,只需用Permission便可表明PermissionAttribute特性。
4、关联特性
利用反射的原理,关联特性类与目标类型(反射:主要利用Type类的属性和方法来得到一个目标类型的类型信息对象,而后根据该对象能够获得目标
类型的信息,如它的字段、属性、方法名、类名等,有了这些信息,下一步就能够随心所欲了,能够还原该类型,即反系列化,甚至建立一个新类型)。
示例代码以下:
class Program { [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class PermissionAttribute : Attribute //类名是特性的名称 { public string compNo; //命名参数 private string _popeId, _popeName; public PermissionAttribute(string popeId,string popeName) //popeId、popeName为定位参数 { compNo = "DB_TEST"; _popeId = popeId; _popeName = popeName; } } [Permission("01_01","用户资料",compNo ="DB_SYSTEM")] public class Users { public Users() { } public int AddUser(string userId,string userName) { return 1; } } static void Main(string[] args) { //一、判断Users类定义时,是否应用了该特性? if (typeof(Users).IsDefined(typeof(PermissionAttribute),false)) { //二、得到该特性对象,以后就能够访问它的成员(元数据)。 PermissionAttribute attribute = (PermissionAttribute)Attribute.GetCustomAttribute(typeof(Users), typeof(PermissionAttribute)); if(attribute.compNo == "DB_SYSTEM") { Console.WriteLine("Hello World."); Console.Read(); } } } }
View Code
运行结果以下:
当编译器发现一个特性应用到一个目标并发生关联时:
1)首先会把"Attribute"追加到特性的名称(若使用了简写),造成完整的特性类名。
2)而后在其全部引入的命名空间中搜索该特性类,若找不到该类或它与目标不匹配时,则产生编译错误。
3)检查传递给特性的参数,并查找该特性中带定位参数的构造函数(或无参构造函数)和其它可选的命名参数(特性类的公共字段、属性),若找到匹配
的构造函数,则实例化该特性类,编译器还会把目标类型的元数据传递给程序集,反射能够从程序集中读取元数据,若找不到则产生编译错误。
关联代码也能够定义在目标类型的内部:
[Permission("01_01","用户资料",compNo ="DB_SYSTEM")] public class Users { public Users() { } public int AddUser(string userId,string userName) { //一、判断Users类定义时,是否应用了该特性? if (typeof(Users).IsDefined(typeof(PermissionAttribute), false)) { //二、得到该特性对象,以后就能够访问它的成员(元数据)。 PermissionAttribute attribute = (PermissionAttribute)Attribute.GetCustomAttribute(typeof(Users), typeof(PermissionAttribute)); if (attribute.compNo == "DB_SYSTEM") { return 1; } } return 0; } }
5、.NET预约义特性
至于.NET预约义特性的实现原理,我没研究过,大概相似自定义特性吧,就好比系列化特性SerializableAttribute,实现原理我想大概是这样:应用
[Serializable]时给目标作一个“标记”,在.NET内置程序集的某个地方判断该目标类型是否应用了该特性,而后决定是否进行系列化操做。