特性(C#)
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签,可以为程序集、类型,以及类型内部的各种成员添加扩展信息,用于表示一些附加信息。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。通常,表示特性的类都派生自System.Attribute类。下面来看几个特殊的特性:
AttributeUsage
预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。
规定该特性的语法如下:
[AttributeUsage(
validon,
AllowMultiple=allowmultiple,
Inherited=inherited
)]
其中:
- 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
- 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
- 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。
例如:
[AttributeUsage(AttributeTargets.Class|
AttributeTargets.Struct|
AttributeTargets.Enum|
AttributeTargets.Delegate|
AttributeTargets.Method|
AttributeTargets.Property|
AttributeTargets.Field|
AttributeTargets.Constructor|
AttributeTargets.Event,
AllowMultiple=true,Inherited=false)]
再看下面代码:
[Serializable]
public class A { }
从上面代码,可以看出,SerializableAttribute特性将应用于A类,在C#中,可以略去“Attribute”,直接写“Serializable”即可。SerializableAttribute类的原型定义如下:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct |
AttributeTargets.Enum | AttributeTargets.Delegate, Inherited = false)]
[ComVisible(true)]
public sealed class SerializableAttribute : Attribute { }
从查看SerializableAttribute类的定义我们又发现,特性类除了从Attribute派生外,也可以向其附加特性,而用的最多的就是AttributeUsageAttribute特性,它的定义如下:
[Serializable]
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
[ComVisible(true)]
public sealed class AttributeUsageAttribute : Attribute { }
在定义AttributeUsageAttribute类时也附加了自身作为类的特性,该类指定特性类的适用范围,用AttributeTargets枚举来表示。
如果特性存在带参数的构造函数,可以在特性后用小括号包裹起来,然后传递参数。当然也可以为特性类的属性或字段赋值,也可以同时加多个特性。
自定义特性
定义特性类与定义普通类一样的,既可以声明构造函数、字段、属性、方法等成员,也可以派生子类,但必须从System.Attribute类或System.Attribute的子类派生。
例如:
[AttributeUsage(AttributeTargets.Class
| AttributeTargets.Method
| AttributeTargets.Property)]
public class MyAttribute : Attribute
{
public string Title { get; set; }
public string VerNo { get; set; }
}
//特性用于类
[My(Title="draw" ,VerNo="1.0.2")]
public class Drawer
{
//特性用于属性
[My(Title = "color", VerNo = "1..0.2")]
public string Color { get; set; }
//特性用于方法
[My(Title = "color", VerNo = "1.0.2")]
public void Draw() { }
//特性用于字段,编译错误
[My(Title = "thick", VerNo = "1.0.2")]
public int a;
}
注意,当MyAttribute特性用于字段时,会发生编译错误,因为MyAttribute类在定义是已经指明它只能用于类、方法、属性,但并未指明其可用于字段。
在默认条件下,特性将应用于更随其后的对象,同理,也可以为方法中的参数应用特性。如下代码所示:
public static string Run([In]string pt,[Optional]int x)
{
return string.Empty;
}
为参数应用特性秩序放在参数前面即可。但是,如果要为返回值应用特性,那么是不是把特性放在返回值前面就可以了呢?就像这样:
public [MarshalAs(UnmanagedType.SysInt] int Compute(){}
这样做是错误的,编译无法通过,那又如何实现呢?
在前面也提到,在默认的情况下,特性是应用于跟随其后的对象的,因此,在许多时候,使用特性是都会省略了表示特性目标的关键字。以下是特性应用于目标对象时的完整格式:
[<目标>:<特性列表>]
下面列举特性目标关键字及相关说明:
assembly:表示特性将应用于当前程序集,通常放在程序集中命名空间或所有类型定义之前。
module:用于当前模块。
field:用于字段,如果特性后紧跟着字段的声明代码,则该关键字可以省略。
event:用于事件。
method:用于方法,也可以用于属性中的get和set访问器。
param:用于方法中的参数或属性定义中的set访问器中的参数(value)。
property:用于属性。
type:用于类型。
return:用于方法的返回值,属性中的get访问器的返回值。
通过上面的介绍,相信你已经知道如何为方法的返回值应用特性了。即将特性应用到方法上,并且注明特性的应用目标为return。如下面代码所示:
[return: MarshalAs(UnmanagedType.SysInt)]
public int Compute() { return ; }
通过反射技术检索特性
下面将介绍如何查找特性,需要用到反射技术。前面讲过,特性可以理解为附加在类型上的扩展信息,可以通过在类型中找到指定的特性来验证代码的调用方法是否符合特定的要求。
下面看个例子即可:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace My
{
[AttributeUsage(AttributeTargets.All)]
public class TypeInfoAttribute : Attribute
{
public string Description { get; set; }
} [TypeInfo(Description = "这是我们定义的枚举类型。")]
enum TestEnum { One = , Two, Three } [TypeInfo(Description = "这是我们定义的一个类。")]
public class Goods { } class Program
{
static void Main(string[] args)
{
// 用Type类的GetCustomAttributes方法可以获取指定类型上附加的特性列表
// 返回一个object类型的数组,数组中的每个元素表示一个特性类的实例
// GetCustomAttributes方法的其中一个重载可以将一个Type作为参数传递
// 该Type表示要获取的特性的类型,typeof运算符返回某个类型的一个Type
// 本例中我们要获取TypeInfoAttribute特性列表
// 由于上面定义TestEnum枚举和Goods类时,只应用了一个TypeInfoAttribute特性
// 因此获取到的特性实例数组的元素个数总为1 object[] attrs = typeof(TestEnum).GetCustomAttributes(typeof(TypeInfoAttribute), false);
if (attrs.Length > )
{
TypeInfoAttribute ti = (TypeInfoAttribute)attrs[];
Console.WriteLine("TestEnum枚举的描述信息:{0}", ti.Description);
} attrs = typeof(Goods).GetCustomAttributes(typeof(TypeInfoAttribute), false);
if (attrs.Length > )
{
TypeInfoAttribute ti = (TypeInfoAttribute)attrs[];
Console.WriteLine("Goods类的描述信息:{0}", ti.Description);
} Console.Read();
}
}
}
结果:
TestEnum枚举的描述信息:这是我们定义的枚举类型。
Goods类的描述信息:这是我们定义的一个类。 通过以上的介绍,相信你已经对特性有了一定的了解。博客写到这里,我也不啰嗦了。
特性(C#)的更多相关文章
- Fis3的前端工程化之路[三大特性篇之声明依赖]
Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...
- Fis3的前端工程化之路[三大特性篇之资源定位]
Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...
- Fis3的前端工程化之路[三大特性篇之内容嵌入]
Fis3版本:v3.4.22 Fis3的三大特性 资源定位:获取任何开发中所使用资源的线上路径 内容嵌入:把一个文件的内容(文本)或者base64编码(图片)嵌入到另一个文件中 依赖声明:在一个文本文 ...
- .NET 4.6.2正式发布带来众多特性
虽然大多数人的注意力都集中在.NET Core上,但与原来的.NET Framework相关的工作还在继续..NET Framework 4.6.2正式版已于近日发布,其重点是安全和WinForms/ ...
- SQL Server 2014 新特性——内存数据库
SQL Server 2014 新特性——内存数据库 目录 SQL Server 2014 新特性——内存数据库 简介: 设计目的和原因: 专业名词 In-Memory OLTP不同之处 内存优化表 ...
- 探索ASP.NET MVC5系列之~~~4.模型篇---包含模型常用特性和过度提交防御
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- InnoDB关键特性学习笔记
插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...
- ElasticSearch 5学习(10)——结构化查询(包括新特性)
之前我们所有的查询都属于命令行查询,但是不利于复杂的查询,而且一般在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,但是,如果想要善用搜索,我们必须使用请求体查询(request ...
- HTML5新特性有哪些,你都知道吗
一.画布(Canvas) 画布是网页中的一块区域,可所以用JavaScript在上面绘图.下面我们来创建一个画布并在上面绘制一个坦克(后面将用HTML5做一个坦克大战游戏),代码如下: <!DO ...
- C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)
#include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...
随机推荐
- Windows驱动开发技术详解HelloWDM例子win7下无法安装
HelloWDM例子编译完成之后,在win7下安装显示 查看setupapi.dev看到如下信息 这个C:\MyDriver_Check目录完全不是我指定的,我放到c盘根目录下 查看inf [Sour ...
- 【三】用Markdown写blog的常用操作
本系列有五篇:分别是 [一]Ubuntu14.04+Jekyll+Github Pages搭建静态博客:主要是安装方面 [二]jekyll 的使用 :主要是jekyll的配置 [三]Markdown+ ...
- 1035-Spell checker(模糊匹配)
一,题意: 给出一组字典的单词,以'#'结束,之后给出一组要执行模糊匹配的单词序列,以'#'结束 1,若某个单词能在字典中找到,则输出corret 2,若某个单词能通过 变换 或 删除 或 添加一个字 ...
- 学习笔记:java并发编程学习之初识Concurrent
一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...
- PostgreSQL 9.3发布
9月9日,PostgreSQL全球开发组宣布了9.3版发布的消息.从2010年9.0版开始,PostgreSQL已经连续四个版本稳定地按时在每年9月中旬发布,从一个侧面也显示了开发团队的强大实力. 9 ...
- 生活中的OO智慧——大话面向对象五大原则
世间万物,以俗眼观纷纷各异,以道眼观种种是常.面向对象思想不仅是编程的智慧,同样也是人生的智慧.通过生活去领悟面向对象的智慧,以面向对象的智慧来指导生活. (部分图片取自How I explained ...
- JavaScript的前世今生
和CSS一样,JavaScript在各浏览器下并非完全一致,它所带来的兼容性问题时常困扰着我们,以至于现在“能否处理流行浏览器的兼容性问题”成为了检验一个程序员是否合格的标准之一.了解JavaScri ...
- Nginx负载均衡的详细配置及使用案例详解.
感谢看过这一些列博文和评论的小伙伴, 我把自己所看到的学到的拿到这里来分享是想和大家一起学习进步, 想听听园友给出的意见, 也是对自己学习过程的一个总结. 技术无止境, 我们仍需努力! 1,话不多说, ...
- Elasticsearch5.0 安装问题集锦
使用Elasticsearch5.0 必须安装jdk1.8 [elsearch@vm-mysteel-dc-search01 bin]$ java -version java version &quo ...
- 前端学PHP之数组函数
× 目录 [1]键值操作 [2]记数[3]回调函数[4]组合[5]栈和队列[6]顺序 前面的话 PHP中的数组功能非常强大,数组处理函数有着强大.灵活.高效的特点.PHP5提供了近100个操作数组的系 ...