特性(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 ...
随机推荐
- PHP中Strict Standards错误解决方法二
在PHP5.3.3 中安装wordpress 3.0.1 ,在安装时出现错误:Strict Standards: PHP Strict Standards: Declaration of Walker ...
- Android安全开发之通用签名风险
Android安全开发之通用签名风险 作者:伊樵.舟海.呆狐@阿里聚安全 1 通用签名风险简介 1.1 Android应用签名机制 阿里聚安全漏洞扫描器有一项检测服务是检测APP的通用签名风险.And ...
- angularjs 指令详解 - template, restrict, replace
通过指令机制,angularjs 提供了一个强大的扩展系统,我们可以通过自定义指令来扩展自己的指令系统. 怎样定义自己的指令呢? 我们通过 Bootstrap UI来学习吧.这个项目使用 angula ...
- 搭建域服务器和DNS
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/域控制器 概述 因为很多高性能高可用方案都会在域环境中组建,所以了解创建域的一些知识对搭建那些高可用方案很有必要. 环境:wind ...
- 解决 Visual Studio 2017 RC 不兼容低版本 Visual Studio 创建的 MVC 4 项目的问题
1.使用文本编辑器(如Visual Studio Code 或 notepad)打开 MVC 4 项目的 .csproj 文件 2.找到代码(可能会有不同)<ProjectTypeGuids&g ...
- Android开发学习之路-Android Studio开发小技巧
上一次发过了一个介绍Studio的,这里再发一个补充下. 我们都知道,Android Studio的功能是非常强大的,也是很智能的.如果有人告诉你学Android开发要用命令行,你可以告诉他Andro ...
- 2013 duilib入门简明教程 -- 自绘控件 (15)
在[2013 duilib入门简明教程 -- 复杂控件介绍 (13)]中虽然介绍了界面设计器上的所有控件,但是还有一些控件并没有被放到界面设计器上,还有一些常用控件duilib并没有提供(比如 ...
- Ajax_01之概述、响应
1.URL.URI和URN URL:Unified Resource Locator:统一资源定位符: URI:Unified Resource Identifier:统一资源识别符: URN:Uni ...
- Angular使用$compile为从Ajax加载的HTML绑定ng-click事件
这是一个Angular使用$compile为从Ajax加载的HTML绑定ng-click事件的实现方式,由于近期忙碌,就先放代码.代码如下: <table data-ng-table=" ...
- Publication的 immediate_sync 属性
Publication的属性 immediate_sync 控制 Snapshot 文件的创建,如果属性 immediate_sync设置为true,那么snapshot file在snapshot ...