【.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高 ...
随机推荐
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
- Python标准库--typing
作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 1 模块简介 Python 3.5 增加了一个有意思的库--typ ...
- 为.NET Core项目定义Item Template
作为这个星球上最强大的IDE,Visual Studio不仅仅提供了很多原生的特性,更重要的是它是一个可定制的IDE,比如自定义Project Template和Item Template就是一个非常 ...
- iOS 键盘添加完成按钮,delegate和block回调
这个是一个比较初级一点的文章,新人可以看看.当然实现这个需求的时候自己也有一点收获,记下来吧. 前两天产品要求在工程的所有数字键盘弹出时,上面带一个小帽子,上面安装一个“完成”按钮,这个完成按钮也没有 ...
- python之最强王者(9)——函数
1.Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但 ...
- StrategyPattern (策略模式)
/** * 策略模式 * @author TMAC-J * 根据环境的不同选择不同的策略,把策略用接口抽象出来 */ public class StrategyPattern { interface ...
- Lucene4.4.0 开发之排序
排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最 ...
- Linux学习笔记(一):常用命令
经过统计Linux中能够识别的命令超过3000种,当然常用的命令就远远没有这么多了,按照我的习惯,我把已经学过的Linux常用命令做了以下几个方面的分割: 1.文件处理命令 2.文件搜索命令 3.帮助 ...
- phpexcel读取输出操作
//读取 <?php header("Content-Type:text/html;charset=utf-8"); include 'Classes/PHPExcel.ph ...
- Configure a VLAN (on top of a bond) with NetworkManager (nmcli) in RHEL7
not on top of a bond Environment Red Hat Enterprise Linux 7 NetworkManager Issue Need an 802.1q VLAN ...