[C#]Attribute特性(3)——AttributeUsage特性和特性标识符
相关文章
[C#]Attribute特性(2)——方法的特性及特性参数
AttributeUsage特性
除了可以定制自己的特性来注释常用的C#类型外,您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例:
[AttributeUsage( Validon, AllowMultiple=allowmultiple, Inherited=inherited )]
您可以非常容易地区别出哪些是定位参数,哪些是命名参数。强烈建议您在记录您的特性时采用这种格式,以便不必通过查看特性类的源代码,您的用户即可以找到哪些公共的读/写字段和属性可以用作命名特性。
定义一个特性目标
现在,让我们再来看看AttributeUsage特性,您会注意到validon参数是一个定位的(必需的)参数。这个参数使您的特性都能附加给哪些类型。确切地说,AttributeUsage特性中的validon参数是AttributeTargets类型的,它事实上是按如下方式定义的一种枚举:
Public enum AttributeTargets
{
// 摘要:
// 可以对程序集应用属性。
Assembly = 0x0001,
//
// 摘要:
// 可以对模块应用属性。
Module = 0x0002,
//
// 摘要:
// 可以对类应用属性。
Class = 0x0004,
//
// 摘要:
// 可以对结构应用属性,即值类型。
Struct = 0x0008,
//
// 摘要:
// 可以对枚举应用属性。
Enum = 0x0010,
//
// 摘要:
// 可以对构造函数应用属性。
Constructor = 0x0020,
//
// 摘要:
// 可以对方法应用属性。
Method = 0x0040,
//
// 摘要:
// 可以对属性 (Property) 应用属性 (Attribute)。
Property = 0x0080,
//
// 摘要:
// 可以对字段应用属性。
Field =0x0100,
//
// 摘要:
// 可以对事件应用属性。
Event = 0x0200,
//
// 摘要:
// 可以对接口应用属性。
Interface = 0x0400,
//
// 摘要:
// 可以对参数应用属性。
Parameter = 0x0800,
//
// 摘要:
// 可以对委托应用属性。
Delegate = 0x1000,
// 摘要:
// 可以对任何应用程序元素应用属性。
All = Assembly|Module|Class|Struct|Enum|Constructor|Method|Property|Field|Event|Interface|Parameter|Delegate,
ClassMember=Class|Struct|Enum|Constructor|Method|Property|Field|Event|Delegate|Interface,
}
AttributeTargets
注意当使用AttributeUsage特性时您可以指定AttributeTargets.All,这样的话,这个特性就可以附加给任何在AttributeTargets枚举中列出的类型了。这是在您不指定AttributeTargets特性时的默认方式。假如AttributeTargets.All是默认值,您可能会觉得奇怪:为什么您还要使用validon值。其原因就是命名参数可以在这个特性上使用,您也许要改变他们其中的一个。但是您要记住:如果您使用了一个命名参数,您必须把它放在所有的定位参数的后面。这可以让您很方便地指定您想使用的特性采用AttributeTargets.All默认值,同时您仍然可以设置它们的命名参数。
那么,在什么时候并且为什么您指定这个validon(AttributeTargets)参数?在任何您想完全控制怎样使用一个特性时,您都可以使用这个参数。在上面的这些例子中,我们创建了一个只有类才能使用的RemoteObjectAttribute特性,还创建了一个只能用在方法上的TransactionableAttribute特性,以及一个只对字段有作用的RegistryKeyAttribute特性。如果我们想让这些特性只注释在设计时它们所注释的那些类型,我们可以这样来定义它们(此处为简明起见略去了特性的主体):
[AttributeUsage(AttributeTargets.Class)]
public class RemoteObjectAttribute:Attribute { ...... }
[AttributeUsage(AttributeTargets.Method)]
public class TransactionableAttribute : Attribute {
public TransactionableAttribute() { }
} [AttributeUsage(AttributeTargets.Field)]
public class RegistryKeyAttribute : Attribute
{
.........
}
最后关于AttributeTargets枚举有一点要提一下:您可以使用“|”操作符来组合成员。如果您有一个既要应用到字段和又要应用到属性的特性,您就可以按如下格式来附加这个AttributeUsage特性:
[AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)]
单次特性和多次特性
您可以用AttributeUsage来把特性定义为单次或者是多次的特性。使用哪种形式取决于一个单的特性在一段单独的字段里的使用次数。在默认形式下,所有的特性都是单次的,这以为着在编译如下代码时将导致一个编译错误:
public class SigleUseAttribute : Attribute
{
public SigleUseAttribute(string str)
{ }
} //Error:This results in a “duplicate attribute ” complier error.
[SigleUse("abc")]
[SigleUse("def")]
public class MyClass
{
......
}
为了解决这个问题,您需要在AttributeUsage那一行指定您要把这个特性多次附加给某些类型。具体方法如下:
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
public class SigleUseAttribute : Attribute
{
public SigleUseAttribute(string str)
{ }
}
[SigleUse("abc")]
[SigleUse("def")]
public class MyClass
{ }
您可能用到这种方法的一个实际例子就是用在“特性的定义”一节中所讨论到的RegistryKeyAttribute特性上。因为我们知道一个字段可能会存储在注册表的多个地方,您可能需要(就像这里的代码一样)通过AllowMultiple 命名参数把AttributeUsage特性附加给它们。
指定继承特性的规则
AttributeUsageAttribute特性的最后一个参数就是他的inherited标记,即用来标识这个特性是否可以继承。它的默认值是false。但是,如果inherited标记被设置成true,那么它还需要看AllowMultiple 标记的值。如果inherited标记为true而AllowMultiple 标记为false,这个特性就不再有继承特性了。不过如果标记是true并且AllowMultiple 标记也是true,这个特性就可以累加到这个成员上。
特性标识符
请看一下下面的代码,并试着标出这个特性是否注释了其中的返回值或方法:
public class MyClass
{
[HRESULT]
public long Foo();
}
如果您具有COM编程经验的话,您就会知道HRESULT是所有错了名为AddRef或Release的方法的基本返回类型。不过,我们可以很容易就明白,如果特性的名字既可以用于返回值又可以用于方法名的或,编译器就不可能知道您的用意到底是什么。下面是编译器不能根据上下文掌握您的真正用意的其他一些情况:
- 方法和返回类型
- 事件、字段和属性
- 委托和返回类型
- 属性、存取器、getter方法的返回值和setter方法的值参数
在这些情况下,编译器根据它所认为的最可能的原则来进行判断。为了不让这种判断出现,您可以使用下面所列出的特性标识符:
- assembly
- module
- type
- method
- property
- event
- field
- param
- return
要使用特性标识符,只需在这个特性名字前面加上所需的标识符和一个冒号即可。在MyClass例子中,如果您想保证编译器能够判断出HRESULT是用来注释返回值而不是其中的方法,您就可以这样指定标识符:
public class MyClass
{
[return:HRESULT]
public long Foo();
}
总结
C#特性提供了这样一种机制,就是在设计时可以用信息来对类型和成员进行注释,并且可以在运行时通过反射来获取这些信息。这使您可以真正创建自我包含的、自我描述的组件,而不必借助于向一些资源文件和常量中填塞一些必须的琐碎信息。这样有利于编出更简单、更易于维护、移植性更强的组件。
本文来自《c#技术内幕》,记录在次,方便自己,方便他人.....
[C#]Attribute特性(3)——AttributeUsage特性和特性标识符的更多相关文章
- C#特性:从自定义一个特性开始,谈谈什么是特性
作为C#新手中的一员,我刚开始接触特性时,那真是一脸冏逼啊,怎么想怎么查资料都没弄明白它到底是个什么东西,有的入门教程甚至都没讲特性和反射这些概念!相信很多人第一次接触到特性就是关于系列化的知识了. ...
- 重新想象 Windows 8.1 Store Apps (84) - 图像处理的新特性, Share Contract 的新特性
[源码下载] 重新想象 Windows 8.1 Store Apps (84) - 图像处理的新特性, Share Contract 的新特性 作者:webabcd 介绍重新想象 Windows 8. ...
- 【ArcGIS 10.2新特性】ArcGIS Online新特性(上)
概述 7月,ArcGIS Online发布了很多更新.主要内容有:新的网站设计,增强了Web制图,数据分析,应用程序创建,以及机构管理等功能. 更新的大致内容总结如下: 地图查看器:新的分析工具.获取 ...
- git与eclipse集成之更新特性分支代码到个人特性分支
1.1. 更新特性分支代码到个人特性分支 在基于特性分支开发的过程中,存在多人向特性分支提交代码的情况,开发者需要关注特性分支代码与个人分支代码保持同步,否则可能导致提交代码冲突. 具体代码同步步骤: ...
- servlet的service特性就是http协议的特性 即连接完就断开
servlet的service特性就是http协议的特性 即连接完就断开
- HTML5 十大新特性(二)——表单新特性
H5的表单新特性可以分为两大类. 一.10个input的type值 1.email:邮件输入域,在表单提交时提供简单的邮箱格式验证,并弹出一个提示窗口. 2.url:地址输入域,在表单提交时提供简单的 ...
- iOS开发——新特性OC篇&Objective新特性
Objective新特性 Overview 自 WWDC 2015 推出和开源 Swift 2.0 后,大家对 Swift 的热情又一次高涨起来,在羡慕创业公司的朋友们大谈 Swift 新特性的同时, ...
- 【特性】MySQL 8 新特性
MySQL 8.0 正式版 8.0.11 已发布,官方表示 MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量的改进和更快的性能! 注意:从 MySQL 5.7 升级到 MySQL 8 ...
- Python3中的新特性(1)——新的语言特性
1.源代码编码和标识符 Python3假定源代码使用UTF-8编码.另外,关于标识符中哪些字符是合法的规则也放宽了.特别是,标识符可以包含代码点为U+0080及以上的任意有效Unico ...
- Java 新特性(4) - JDK 8 新特性
http://www.360doc.com/content/14/0620/11/1370831_388286071.shtml
随机推荐
- ELK 信息统计分析-2
Range 按数值类型的字段聚合统计 { "query": { "match_all": {} }, "aggs": { "ter ...
- MIT jos 6.828 Fall 2014 训练记录(lab 6)
源代码参见我的github: https://github.com/YaoZengzeng/jos 在这个实验中将实现一个基于Intel 82540M(又称E1000)的网卡驱动.不过,一个网卡驱动还 ...
- 矩阵乘法 codevs 1287 矩阵乘法
1287 矩阵乘法 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 小明最近在为线性代数而头疼,线性代数确实很抽象 ...
- UESTC 918 WHITE ALBUM --生成树变形
最小生成树变形. 题目已经说得很清楚,要求到达每个房间,只需求一个最小生成树,这时边权和一定是最小的,并且那k个房间一定与所有点都有通路,即一定都可以逃脱. 但是有可能当所有点都有了该去的安全房间以后 ...
- 2014 Super Training #7 B Continuous Login --二分
原题:ZOJ 3768 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3768 一个结论:一个正整数总能用不超过三个前n项相 ...
- HDU 4406 最大费用最大流
题意:现有m门课程需要复习,已知每门课程的基础分和学分,共有n天可以复习,每天分为k个时间段,每个时间段可以复习一门课程,并使这门课程的分数加一,问在不挂科的情况下最高的绩点. 思路:(没做过费用流的 ...
- 安全框架 - Shiro与springMVC整合的注解以及JSP标签
Shiro想必大家都知道了,之前的文章我也有提过,是目前使用率要比spring security都要多的一个权限框架,本身spring自己都在用shiro,之前的文章有兴趣可以去扒一下 最近正好用到s ...
- centos下pip安装mysql_python
今天在使用pip安装mysql_python时,遇到一些问题,现记录下来. 1.执行pip install mysql-python时,报错 Running setup.py egg_info for ...
- Selenium Webdriver元素定位的八种常用方式
楼主原创,欢迎学习和交流,码字不容易,转载请注明出处,谢谢. 在使用selenium webdriver进行元素定位时,通常使用findElement或findElements方法结合By类返回的元素 ...
- Python 栅栏凯撒
def fence_Crypto(msg,priority="row"): ''' usage: fence_Crypto(msg[, priority])->msg to ...