【.net 深呼吸】自定义特性(Attribute)的实现与检索方法
在.net的各个语言中,尤其是VB.NET和C#,都有特性这一东东,具体的概念,大家可以网上查,这里老周说一个非标准的概念——特性者,就是对象的附加数据。对象自然可以是类型、类型成员,以及程序集。
说简单点,就是你在定义一些代码时,希望为某个代码对象加上一些额外的内容,但这些内容又不便在代码中直接写。比如,你为B类定义了一个 int 类型的属性P,而且是个虚属性,就是B的派生类可以重写它。我希望可以给这个属性弄个版本号,当子类override这个属性时,给它记一个版本号,然后在其他代码中访问这个属性时,可以检查一下版本号,比如当版本号小于3时,抛出异常,不让使用。
另外比如,当某个类的某个成员在后续版本中会删除时,也可以使用特性来附加一个说明,好让调用代码识别,在.net类库中常用这种方法。在比如,可以给某些对象加上免调试的特性,当调用代码时,遇到带有这些特性的对象时就跳过调试。
除了API库给出的特性外(特性类通常以Attribute结尾),我们也可以根据需要,自己定义特性类。
自定义特性的定义和一般类的定义差不多,不过要注意两点:一是应该从Attribute类或其子类派生,一般是直接从Attribute类派生;二是,不管是不是直接派生自Attribute类,只要是特性类,都要在该类的定义上附加AttributeUsageAttribute特性,作用是指明你定义的这个特性的应用范围。
啥意思呢,就是你这个特性能用在哪些对象上,比如这个特性只能用在方法上,那就把AttributeTargets值设为Method,如果只希望特性只用在类上,就指定Class;要是希望特性可以同时用在属性和方法上,就把Method和Property值组合起来。如果打算让这个特性成为“万能”通,那就用值All,表示特性可以用在所有代码对象上。
下面,还是举个例子吧。假设我定义了这个特性。别管它干吗用的,反正只是个示例。
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
public class AssRateAttribute : Attribute
{
ushort m_rate;
public AssRateAttribute(ushort rate)
{
m_rate = rate;
} public ushort Rate
{
get { return m_rate; }
}
}
这里我指定了,它只能用于程序集,为啥选的程序集呢,因为它比较特殊,待会儿老周顺便介绍一下如何给程序集附加特性。
还有两个属性,一个是Inherited,就是说这个特性是否可以被继承,当然,对于程序集而言,无所谓。不过,如果这个特性是用在类、类型成员上,就可以用上,我把这个特性用在某对象,它的派生类是否继承这个特性。要是设置为false,那么这个特性只有附加的目标类型上可以检索到,而在类型的派生类上是检索不到的。
AllowMultiple指定该特性是否可以在同一个对象上多次使用。如果为false,那在附加时只能用一次,比如,下面的用法是会报错的。
[AssRate()]
[AssRate()]
public class C
{ }
因为上面的C类上,AssRateAttribute特性用了两次,就会出错。如果希望它可以多个实例并用,就把AllowMultiple属性改为true。当然,上面的代码只是假设,因为AssRateAttribute是不能用在类上的,它已指明只能用在程序集上。
接下来,看看如何把特性贴到程序集上,程序集的特性用法比较特殊,因为它没有实体代码,只是个逻辑组合,因此,你听好了:请把用于程序集的特性,写在所有代码的前面。
就是说,如果你的代码文件前面写了代码,那就不能再为程序集加特性了。例如这样是不对的。
namespace Test{
....
public class DocumentsOpt{ .... }
}
[assembly:AssRate()]
这样做是错的,因为前面已经有代码了,再为程序集附加特性是不可以的。
正确的do法是这样的:
[assembly:AssRate()] using System;
using System.IO;
namespace Test{
....
public class DocumentsOpt{ .... }
}
特性前面的assembly: 是啥意思呢,其实,特性的完整语法应该如下:
[ <target:> <attributes....> ]
例如要把特性用在类上,可以写上:
[class: MyAttr ]
不过,对于类,我们一般是可以省掉target,因为我们会在类的定义前面写上特性,这样编译器也能识别出来是附加到类上的。
根据老周耍.net的多年经验,只有两种情况下才要写上target,其余情况可以省略。
1、方法的返回值,因为这个特性虽然用在方法的返回值上,但是它只能写在方法的定义前,为了告诉编译器,这个特性不是给方法的,是给返回值的,所以要写上return,就像这样:[return: Attris...]。
2、程序集,因为程序集是逻辑性的,不存在实体的代码对象,只能明确指定特性是用在程序集上的,即[assembly: MyAttr]。
那么如何确保用于程序集的特性都能在所有代码之前呢,VS在项目中弄了这个结构,与项目本身有关的,都放在Properties节点下,其中有个代码文件叫AssemblyInfo.cs,或者AssemblyInfo.vb,这个文件不写其他的代码,只用来放程序集的特性。就像这样:
[assembly: AssemblyTitle("app")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("app")]
[assembly: AssemblyCopyright("Copyright © 老周 2016")]
所以,我们刚刚定义的AssRateAttribute特性就要写在这个文件里。
[assembly: AssRate()]
为什么特性类要以Attribute结尾,除了便于识别,也看到在代码中使用时,可以省略Attribute。
那么,特性应用之后,我们在运行阶段如何检索呢,这个嘛,你想啊,要动态知道对象的结构和信息,该用啥技术?对了,反射。就像你照镜子那样,可以把你的嘴脸呈现在镜子中,然后你就能看到自己了,道理一样,反射就是给代码照镜子用的,你可以运行时知道代码的结构,尽管代码已经编译了。
比如下面的方法,检测我们刚定义的特性,看看特性指定的Rate值,然后做出响应。
static void Check()
{
Assembly currassembly = Assembly.GetExecutingAssembly();
AssRateAttribute att = currassembly.GetCustomAttribute<AssRateAttribute>();
if (att != null)
{
if (att.Rate <)
{
throw new InvalidOperationException("程序集人品分太低,禁止使用。");
}
else
{
Console.WriteLine("程序集人品分合格。");
}
}
}
反射API定义了多个GetCustomAttribute或,GetCustomAttributes方法,用来检索特性实例,这些方法包括多种扩展方法,我就不一一介绍,自己查MSDN和对象浏览器。如果在定义特性类时指明了它允许多个实例,就用GetCustomAttributes方法来获取多个实例,如果AllowMultiple为False,只允许单一实例,就用GetCustomAttribute方法获取单个特性实例。获取到特性实例后就可以进行验证或处理了。
好,本文内容就扯到这里了。哦,关于示例源代码嘛,不提供,想玩的话,自己动手写。
【.net 深呼吸】自定义特性(Attribute)的实现与检索方法的更多相关文章
- 如何获取类或属性的自定义特性(Attribute)
如何获取类或属性的自定义特性(Attribute) 问题说明: 在ActiveRecord或者其他的ORM等代码中, 我们经常可以看到自定义特性(Attribute)的存在(如下面的代码所示) [Pr ...
- C# 自定义特性Attribute
一.特性Attribute和注释有什么区别 特性Attribute A:就是一个类,直接继承/间接继承Attribute B:特性可以在后期反射中处理,特性本身是没有什么*用的 C:特性会影响编译和运 ...
- C# 自定义特性(Attribute)详解
什么是特性 特性的定义:公共语言运行时允许添加类似关键字的描述声明,叫做attribute,它对程序中的元素进行标注,如类型.字段.方法.和属性等.attribute和.NetFramework文件的 ...
- [C#] C# 知识回顾 - 特性 Attribute
C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...
- .Net 特性 attribute 学习 ----自定义特性
什么是特性? [Obsolete("不要用无参构造函数",true)] 放在方式上, 该方法就不能使用了 [Serializable]放在类上面.该类就是可以序列化和反序列化使用 ...
- 代码走查25条疑问 C# 跳转新的标签页 C#线程处理 .Net 特性 attribute 学习 ----自定义特性 看懂 ,学会 .NET 事件的正确姿势-简单版
代码走查25条疑问 代码走查(Code Review) 是一个开发人员与架构师集中讨论代码的过程.通过代码走查可以提高代码的 质量,同时减少Bug出现的几率.但是在小公司中并没有代码走查的过程在这 ...
- C#提高--------------获取方法返回值的自定义特性(Attribute)
.NET(C#):获取方法返回值的自定义特性(Attribute) 转载 2013年05月08日 10:54:42 1456 来自:http://www.cnblogs.com/mgen/archiv ...
- Attribute自定义特性+Asp.net MVC中的filter详解
转载自:http://blog.csdn.net/wangyy130/article/details/44241957 一.filter简介 在了解自定义特性前,先引入一个概念filter,它是MVC ...
- 区分元素特性attribute和对象属性property
× 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...
随机推荐
- 在 ML2 中配置 OVS flat network - 每天5分钟玩转 OpenStack(133)
前面讨论了 OVS local network,今天开始学习 flat network. flat network 是不带 tag 的网络,宿主机的物理网卡通过网桥与 flat network 连接, ...
- 高频交易算法研发心得--MACD指标算法及应用
凤鸾宝帐景非常,尽是泥金巧样妆. 曲曲远山飞翠色:翩翩舞袖映霞裳. 梨花带雨争娇艳:芍药笼烟骋媚妆. 但得妖娆能举动,取回长乐侍君王. [摘自<封神演义>纣王在女娲宫上香时题的诗] 一首定 ...
- JAVA程序员常用软件整理下载
********为了大家学习方便,特意整理软件下载如下:*************Java类软件:-------------------------------JDK7.0:http://pan.ba ...
- addTwoNumbers
大神的代码好短,自己写的120多行=_= 各种判断 ListNode *f(ListNode *l1, ListNode *l2) { ListNode *p1 = l1; ListNode *p2 ...
- 浅谈java异常[Exception]
学习Java的同学注意了!!! 学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java! 一. 异常的定义 在<java编程思想 ...
- SymmetricDS 快速和灵活的数据库复制
开始谈谈开源的SymmetricDS,谈谈实际使用中,遇到的一些问题和解决办法.持续更新: SymmetricDS 快速和灵活的数据库复制 实际使用 和 埋过的坑 (一)知识篇 SymmetricDS ...
- VMware安装CentOS
centos镜像地址:https://www.centos.org/download/ VMware版本:12.5.2 build-4638234 创建新的虚拟机 直接默认下一步 稍后安装操作系统-& ...
- 用 eric6 与 PyQt5 实现python的极速GUI编程(系列04)---- PyQt5自带教程:地址簿(address book)
[引子] 在PyQt5自带教程中,地址簿(address book)程序没有完全实现界面与业务逻辑分离. 本文我打算用eric6+PyQt5对其进行改写,以实现界面与逻辑完全分离. [概览] 1.界面 ...
- [转]Java常用工具类集合
转自:http://blog.csdn.net/justdb/article/details/8653166 数据库连接工具类——仅仅获得连接对象 ConnDB.java package com.ut ...
- Unity AssetBundle爬坑手记
这篇文章从AssetBundle的打包,使用,管理以及内存占用各个方面进行了比较全面的分析,对AssetBundle使用过程中的一些坑进行填补指引以及喷! AssetBundle是Unity推荐的 ...