C#中Attribute特性的用法

开篇语

本文开始之前,首先我想问下大家对于属性和特性知道多少?属性和特性又有何区别?

对于该单词,我更想把它称之为:特性。对于属性和特性就是名称上有纠葛(不知道你们迷不迷,反正我写本文之前我是迷了),什么是属性?属性是面向对象编程的基本概念,提供了对私有字段的访问封装,在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 对象和任何其他特性对象

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#自定义特性(Attribute)详解

    在前面介绍的代码中有使用特性,这些特性都是Microsoft定义好的,作为.NET Framework类库的一部分,许多特性都得到了C#编译器的支持..NET Frmework也允许定义自己的特性.自定义特性允许把自定义元数据与程序元素关联起来.这些元数据是在编译过程中创建的,并嵌入到程序集中.这些特性不会影响编译过程,因为编译器不能识别它们,但这些特性在应用于程序元素时,可以在编译好的程序集中用作元数据.这些元数据在文档说明中很有用.使自定义特性起很大作用的是反射(https://www.jb

  • C#特性(Attribute)

    一.什么是特性 特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签.您可以通过使用特性向程序添加声明性信息.一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的. 特性(Attribute)用于添加元数据,如编译器指令和注释.描述.方法.类等其他信息..Net 框架提供了两种类型的特性:预定义特性和自定义特性. 特性的语法如下: [attribute(positional_parameters, name_par

  • C#中枚举的特性 FlagAttribute详解

    写在前面 枚举Enum 全称(Enumeration),即一种由一组称为枚举数列表的命名常量组成的独特类型.可以看出枚举的出现时为了使我们可以在程序中方便的使用一些特定值的常量,一般的使用大家都比较熟悉,本文主要介绍枚举的特性 FlagAttribute. FlagAttribute是什么? Flag 特性微软的解释是:指示可以将枚举作为位域(即一组标志)处理,FlagsAttribute属性就是枚举类型的一项可选属性,它的主要作用是可以将枚举作为位域处理(P.S. C#不支持位域).所谓位域是

  • C#中Attribute特性的用法

    开篇语 本文开始之前,首先我想问下大家对于属性和特性知道多少?属性和特性又有何区别? 对于该单词,我更想把它称之为:特性.对于属性和特性就是名称上有纠葛(不知道你们迷不迷,反正我写本文之前我是迷了),什么是属性?属性是面向对象编程的基本概念,提供了对私有字段的访问封装,在C#中以get和set访问器方法实现对可读可写属性的操作,提供了安全和灵活的数据访问封装.什么是特性?下面内容就说明下: 介绍 使用特性,可以有效地将元数据或声明性信息与代码(程序集.类型.方法.属性等)相关联.将特性与程序实体

  • jQuery中[attribute^=value]选择器用法实例

    本文实例讲述了jQuery中[attribute^=value]选择器用法.分享给大家供大家参考.具体分析如下: 此选择器能够选取属性值是以某些值开始的元素. 语法结构: 复制代码 代码如下: $("[attribute^=value]") 参数列表: 参数 描述 attribute 属性名称. value 元素数属性开始的值. 引号在大多数情况下是可选的.但在遇到诸如属性值包含"]"时,用以避免冲突. 实例代码: 实例一: 复制代码 代码如下: <!DOCT

  • jQuery中[attribute]选择器用法实例

    本文实例讲述了jQuery中[attribute]选择器用法.分享给大家供大家参考.具体分析如下: 此选择器能够匹配带有给定属性的元素. 语法结构: 复制代码 代码如下: $("[attribute]") 参数列表: 参数 描述 attribute 要查找的属性名称. 实例代码: 复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <m

  • JSP中EL表达式的用法详解(必看篇)

    EL 全名为Expression Language EL 语法很简单,它最大的特点就是使用上很方便.接下来介绍EL主要的语法结构: ${sessionScope.user.sex} 所有EL都是以${为起始.以}为结尾的.上述EL范例的意思是:从Session的范围中,取得 用户的性别.假若依照之前JSP Scriptlet的写法如下: User user =(User)session.getAttribute("user"); String sex =user.getSex( );

  • 详解C/C++中const关键字的用法及其与宏常量的比较

    1.const关键字的性质 简单来说:const关键字修饰的变量具有常属性. 即它所修饰的变量不能被修改. 2.修饰局部变量 const int a = 10; int const b = 20; 这两种写法是等价的,都是表示变量的值不能被改变,需要注意的是,用const修饰变量时,一定要给变量初始化,否则之后就不能再进行赋值了,而且编译器也不允许不赋初值的写法: 在C++中不赋初值的表达一写出来,编译器即报错,且编译不通过. 在C中不赋初值的表达写出来时不报错,编译时只有警告,编译可以通过.而

  • JAVA中的final关键字用法实例详解

    本文实例讲述了JAVA中的final关键字用法.分享给大家供大家参考,具体如下: 根据上下文环境,java的关键字final也存在着细微的区别,但通常指的是"这是无法改变的."不想改变的理由有两种:一种是效率,另一种是设计.由于两个原因相差很远,所以关键子final可能被误用. 接下来介绍一下使用到final的三中情况:数据,方法,类 final数据 许多编程语言都有某种方法,来向编译器告知一块数据是恒定不变的.有时数据的恒定不变是很有用的,例如: 1. 一个编译时恒定不变的常量 2.

  • Asp.Net中索引器的用法分析

    本文实例分析了Asp.Net中索引器的用法.分享给大家供大家参考.具体如下: 索引器定义类似于属性,但其功能与属性并不相同.索引器提供一种特殊的方法编写get和set访问器.属性可以像访问字段一样访问对象的数据,索引器可以使用户像访问数组一样访问类成员. 一.索引器特性 1.get 访问器返回值.set 访问器分配值. 2.this 关键字用于定义索引器. 3.value 关键字用于定义由 set 索引器分配的值. 4.索引器不必根据整数值进行索引,由您决定如何定义特定的查找机制. 5.索引器可

  • 浅谈JS中逗号运算符的用法

    注意: 一.由于目前正在功读JavaScript技术,所以这里拿JavaScript为例.你可以自己在PHP中试试. 二.JavaScript语法比较复杂,因此拿JavaScript做举例. 最近重新阅读JavaScript权威指南这本书,应该说很认真的阅读,于是便想把所学的东西多记录下来.后 面本人将逐步写上更多关于本书的文章. 本文的理论知识来自于JavaScript权威指南,我这里做一下整理,或者说叫笔记. 如果你的基础够好的话,完全理解不成问题,但是如果读得有些郁闷的话,可以加我的QQ:

  • python中list循环语句用法实例

    本文实例讲述了python中list循环语句用法.分享给大家供大家参考.具体用法分析如下: Python 的强大特性之一就是其对 list 的解析,它提供一种紧凑的方法,可以通过对 list 中的每个元素应用一个函数,从而将一个 list 映射为另一个 list. 实例 复制代码 代码如下: a = ['cat', 'window', 'defenestrate'] for x in a:      print x, len(x) for x in [1, 2, 3]: print x,    

  • JQuery中属性过滤选择器用法实例分析

    本文实例讲述了JQuery中属性过滤选择器用法.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <he

随机推荐