C#中Attribute特性的用法
作者:AZRNG
开篇语
本文开始之前,首先我想问下大家对于属性和特性知道多少?属性和特性又有何区别?
对于该单词,我更想把它称之为:特性。对于属性和特性就是名称上有纠葛(不知道你们迷不迷,反正我写本文之前我是迷了),什么是属性?属性是面向对象编程的基本概念,提供了对私有字段的访问封装,在C#中以get和set访问器方法实现对可读可写属性的操作,提供了安全和灵活的数据访问封装。什么是特性?下面内容就说明下:
介绍
使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。将特性与程序实体相关联后,可以在运行时使用 反射 这项技术查询特性。详情 用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
简单总结:定制特性attribute,本质上是一个类,其为目标元素提供关联附加信息,并在运行期以反射的方式来获取附加信息。
常用特性
AttributeUsage
AttributeUsage特性用于控制如何应用自定义特性到目标元素,有三个数据属性可用以修饰我们的自定义的属性
ValidOn | 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。 |
---|---|
AllowMultiple | 定义了是否可在同一个程序实体上同时使用多个属性进行修饰 |
Inherited | 定义了自定义属性的修饰是否可由被修饰类的派生类继承 |
[AttributeUsage(validOn: AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class HelpAttribute : Attribute { }
表示该特定只能标识在类上,并且同一个类上只能用一个属性修饰,并且自定义属性的修饰不能由修饰类的派生类继承。
Flags
以Flags特性来将枚举数值看作位标记,而非单独的数值,例如我有如下的一个需求,当我想要取得用户信息的时候,会先从本地缓存中查找,找不到然后从分布式缓存中查找,最后找不到再从数据库中查询。但是有些场景我又不需要查询数据库。
所以会建立下面的这种模型
public UserEntity GetUserInfo(List<DataSource> dataSources) { var xxxx = new UserEntity(); if(dataSources.Any(DataSource.Local) { //从本地缓存中获取 return xxxx; } if(dataSources.Any(DataSource.Distribution) { //从分布式缓存中获取 //更新本地缓存 return xxxx; } if(dataSources.Any(DataSource.DB) { //从DB中获取 //更新分布式缓存 //更新本地缓存 } return xxxx; }
但是每次调用者都去构建一个List,比较麻烦,此时我们可以使用枚举中的Flags特性,修改程序如下:
首先是枚举的定义上,要加上 [Flags] 特性标签,并且定义 一般都是 2的n次方,主要是便于位移运算
/// <summary> ///数据取得地方 /// </summary> [Flags] public enum DataSource { /// <summary> ///本地缓存 /// </summary> [Description("本地缓存")] LocalCache = 1, /// <summary> ///分布式缓存 /// </summary> [Description("分布式缓存")] DistributeCache = 2, /// <summary> ///数据库 /// </summary> [Description("数据库")] DB = 4, }
修改代码
public UserEntity GetUserInfo(DataSource dataSources) { var xxxx = new UserEntity(); if(dataSources.HasFlags(DataSource.Local) { //从本地缓存中获取 return xxxx; } if(dataSources.HasFlags(DataSource.Distribution) { //从分布式缓存中获取 //更新本地缓存 return xxxx; } if(dataSources.HasFlags(DataSource.DB) { //从DB中获取 //更新分布式缓存 //更新本地缓存 } return xxxx; }
调用的地方,可以用过“|”来指定,例如我只想用分布式缓存和数据库,那么:
var userInfo = GetUserInfo(DataSource.Distribution | DataSource.DB);
该例子摘抄自:https://www.jb51.net/article/254408.htm
DllImport
DllImport特性,可以让我们调用非托管代码,所以我们可以使用DllImport特性引入对Win32 API函数的调用
[System.Runtime.InteropServices.DllImport("user32.dll")] extern static void SampleMethod();
Serializable
Serializable特性表明了应用的元素可以被序列化(serializated)
[Serializable] public class SampleClass { // Objects of this type can be serialized. }
Conditional
Conditional特性,用于条件编译,在调试时使用。注意:Conditional不可应用于数据成员和属性。
自定义特性
可通过定义特性类创建自己的自定义特性,特性类是直接或间接派生自 Attribute 的类,可快速轻松地识别元数据中的特性定义。假设我们希望使用编写类的程序员名字来标记该类,那么我们就需要自定义一个Author特性类
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] public class AuthorAttribute : Attribute { public string AuthorName; public double version; public AuthorAttribute(string authorName) { this.AuthorName = authorName; version = 1.0; } }
类名 AuthorAttribute
是该特性的名称,即 Author
加上 Attribute
后缀。由于该类继承自 System.Attribute
,因此它是一个自定义特性类。构造函数的参数是自定义特性的位置参数。在此示例中,name
是位置参数。所有公共读写字段或属性都是命名参数。在本例中,version
是唯一的命名参数。
请注意,使用
AttributeUsage
特性可使Author
特性仅对类和struct
声明有效。
可按照下面的方式使用特性
[Author("张三", version = 1.1)] [Author("李四", version = 1.2)] public class SampleClass { // 业务逻辑代码 }
获取自定义参数
var attr = typeof(SampleClass).GetCustomAttributes(typeof(AuthorAttribute), true);
GetCustomAttributes 会以数组形式返回 Author 对象和任何其他特性对象
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。