一、什么是特性?

特性(attribute)是被指定给某一声明的一则附加的声明性信息。

在C#中,有一个小的预定义特性集合。在学习如何建立我们自己的定制特性(custom attributes)之前,我们先来看看在我们的代码中如何使用预定义特性。

using System;
public class AnyClass
{
[Obsolete("Don't use Old method, use New method", true)]
static void Old( ) { }
static void New( ) { }
public static void Main( )
{
Old( );
}
}

我们先来看一下上面这个例子,在这个例子中我们使用了Obsolete特性,它标记了一个不应该再被使用的程序实体。第一个参数是一个字符串,它解释了为什么该实体是过时的以及应该用什么实体来代替它。实际上,你可以在这里写任何文本。第二个参数告诉编译器应该把使用这个过时的程序实体当作一种错误。它的默认值是false,也就是说编译器对此会产生一个警告。

当我们尝试编译上面这段程序的时候,我们将会得到一个错误:   

AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'

二、自定义特性

除了C#中系统自带的特性外我们可以自己定义一些特性。所有自定义的Attribute必须从Attribute类派生,命名也是要以Attribute结尾,在使用的时候可以省略Attribute。

特性类的使用过程:

第一步:定义一个特性类,定义一些成员来包含验证时需要的数据;

第二步:创建特性类实例;

创建一个特性类的实例,里面包含着验证某一个属性或者字段需要的数据。

将该实例关联到某个属性上面。

第三步:使用特性类实例

可以通过调用某个类型的GetProperties()方法,获取属性,

然后调用类型属性成员的GetCustomAttributes()方法,获取该属性关联的特性类实例,

然后使用查找到的特性类实例验证新建对象。

第一步:定义一个特性类,定义一些成员来包含验证时需要的数据;


第二步:创建一个特性类的实例,并关联一个属性

public class Order
{
[StringLength("订单号", , MinLength = , ErrorMessage = "{0}的长度必须在{1}和{2}之间!")]//实例化一个特性类,关联到一个字段上面
public string OrderID { get; set; }
}

第三步:使用特性类实例,进行验证

class Program
{
#region 使用特性类的过程 //验证过程
//1.通过映射,找到成员属性关联的特性类实例,
//2.使用特性类实例对新对象的数据进行验证 //用特性类验证订单号长度
public static bool isIDLengthValid(int IDLength, MemberInfo member)
{
foreach (object attribute in member.GetCustomAttributes(true)) //2.通过映射,找到成员属性上关联的特性类实例,
{
if (attribute is StringLengthAttribute)//3.如果找到了限定长度的特性类对象,就用这个特性类对象验证该成员
{
StringLengthAttribute attr = (StringLengthAttribute)attribute;
if (IDLength < attr.MinLength || IDLength > attr.MaxLength)
{
string displayName = attr.DisplayName;
int maxLength = attr.MaxLength;
int minLength = attr.MinLength;
string error = attr.ErrorMessage;
Console.WriteLine(error, displayName,maxLength, minLength);//验证失败,提示错误
return false;
}
else return true;
} }
return false;
} //验证订单对象是否规范
public static bool isOrderValid(Order order)
{
if (order == null) return false;
foreach (PropertyInfo p in typeof(Order).GetProperties())
{
if (isIDLengthValid(order.OrderID.Length, p))//1记录下新对象需要验证的数据,
return true;
}
return false; }
#endregion
public static void Main()
{
Order order=new Order();
do
{
Console.WriteLine("请输入订单号:");
order.OrderID= Console.ReadLine();
}
while (!isOrderValid(order));
Console.WriteLine("订单号输入正确,按任意键退出!");
Console.ReadKey();
} }

总结:特性类的实例里没有验证逻辑,只有验证用到的规范数据(比如字符串长度)、提示信息等。验证逻辑需要自己写。

三、定义或控制特性的使用

AttributeUsage类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述了一个定制特性如和被使用。

AttributeUsage有三个属性,我们可以把它放置在定制属性前面。第一个属性是:

ValidOn

通过这个属性,我们能够定义定制特性应该在何种程序实体前放置。一个属性可以被放置的所有程序实体在AttributeTargets enumerator中列出。通过OR操作我们可以把若干个AttributeTargets值组合起来。

AllowMultiple

这个属性标记了我们的定制特性能否被重复放置在同一个程序实体前多次。

Inherited

我们可以使用这个属性来控制定制特性的继承规则。它标记了我们的特性能否被继承。

下面让我们来做一些实际的东西。我们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。

using System;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}

先让我们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:

[Help("this is a do-nothing class")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}

编译器报告错误如下:

AnyClass.cs: Attribute 'Help' is not valid on this declaration type.

It is valid on 'class' declarations only.

我们可以使用AttributeTargets.All来允许Help特性被放置在任何程序实体前。可能的值是:

Assembly,Module,Class,Struct,Enum,Constructor,Method,Property,Field,Event,Interface,Parameter,Delegate

All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate

ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface

下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置多次。

[Help("this is a do-nothing class")]
[Help("it contains a do-nothing method")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}

它产生了一个编译期错误。

AnyClass.cs: Duplicate 'Help' attribute

Ok,现在我们来讨论一下最后的这个属性。Inherited, 表明当特性被放置在一个基类上时,它能否被派生类所继承。

[Help("BaseClass")]
public class Base
{
}
public class Derive : Base
{
}

这里会有四种可能的组合:

1 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 
2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
3 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
4 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]

第一种情况:

如果我们查询(Query)(稍后我们会看到如何在运行期查询一个类的特性)Derive类,我们将会发现Help特性并不存在,因为inherited属性被设置为false。

第二种情况:

和第一种情况相同,因为inherited也被设置为false。

第三种情况:

为了解释第三种和第四种情况,我们先来给派生类添加点代码:

[Help("BaseClass")]
public class Base
{
}
[Help("DeriveClass")]
public class Derive : Base
{
}

现在我们来查询一下Help特性,我们只能得到派生类的属性,因为inherited被设置为true,但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。

第四种情况:

在这里,我们将会发现派生类既有基类的Help特性,也有自己的Help特性,因为AllowMultiple被设置为true。

定义或控制特性的使用AttributeUsage类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述了一个定制特性如何被使用。

属性和特性的区别可以参考一下: http://developer.51cto.com/art/200908/147097.htm

特性(attribute)的更多相关文章

  1. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

  2. [C#] C# 知识回顾 - 特性 Attribute

    C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...

  3. C# 知识特性 Attribute

    C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用"反射"查询 ...

  4. 区分元素特性attribute和对象属性property

    × 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...

  5. .Net内置特性Attribute介绍

    特性Attribute概述 特性(Attribute)是一种特殊的类型,可以加载到程序集或者程序集的类型上,这些类型包括模块.类.接口.结构.构造函数.方法.字段等,加载了特性的类型称之为特性的目标. ...

  6. 【点滴积累】通过特性(Attribute)为枚举添加更多的信息

    转:http://www.cnblogs.com/IPrograming/archive/2013/05/26/Enum_DescriptionAttribute.html [点滴积累]通过特性(At ...

  7. 理解特性attribute 和 属性property的区别 及相关DOM操作总结

    查一下英语单词解释,两个都可以表示属性.但attribute倾向于解释为特质,而property倾向于解释私有的.这个property的私有解释可以更方便我们下面的理解. 第一部分:区别点 第一点:  ...

  8. 如何获取类或属性的自定义特性(Attribute)

    如何获取类或属性的自定义特性(Attribute) 问题说明: 在ActiveRecord或者其他的ORM等代码中, 我们经常可以看到自定义特性(Attribute)的存在(如下面的代码所示) [Pr ...

  9. C# 知识特性 Attribute,XMLSerialize,

    C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用“反射”查询特性,获取特性集合方 ...

  10. c#特性attribute:

    特性是被编译到metadata中,  是提供给反射用的. 特性attribute:1 什么是attribute,和注释有什么区别 2 声明和使用attribute3 使用attribute完成扩展4 ...

随机推荐

  1. JS实现大整数乘法(性能优化、正负整数)

    本方法的思路为: 一:检查了输入的合法性(非空,无非法字符) 二:检查输入是否可以进行简单计算(一个数为 0,1,+1,-1) 三:去掉输入最前面可能有的正负符号,并判断输出的正负 四:将输入的值分成 ...

  2. 深入理解Java中停止线程

    一.停止线程会带来什么? 对于单线程中,停止单线程就是直接使用关键字return或者break,但是在停止多线程时是让线程在完成任务前去开启另外一条线程,必须放弃当前任务,而这个过程是不可预测,所以必 ...

  3. Unity C#图片转换二进制流、字符串互转

    图片转二进制流转换图片互转 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享. ...

  4. 跨源资源共享(CORS)概念、实现(用Spring)、起源介绍

    本文内容引用自: https://howtodoinjava.com/spring5/webmvc/spring-mvc-cors-configuration/ https://developer.m ...

  5. .net平台常用组建

    常用的一些开源组件整理: 导出Excel报表的插件:NOPI.dll(基于微软OpenXml实现)开源的作业调度和自动任务框架:Quartz.NET用于大数据搜索引擎的全文检索框架:Lucene.ne ...

  6. N阶乘尾部的0个数

    N阶乘尾部的0个数 描述 设计一个算法,计算出n阶乘中尾部零的个数 思路: 1.1 * 2 * 3 * ... * n --> 1 * 2 * 3 * (2 * 2) * 5 * (2 * 3) ...

  7. go-json处理的问题

    1.通过Decoder来解析json串 package main import ( "encoding/json" "fmt" "io" & ...

  8. linux服务器架设--学习笔记

    PS: Centos是属于红帽子的操作系统

  9. IIS 集成模式 导致 AjaxPro 无法正常运行

    web.config 配置如下: system.web/httphandlers <httpHandlers> <add verb="POST,GET" path ...

  10. spring中使用@PostConstruct和@PreConstruct注解

    1.@PostConstruct说明 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法.被@PostCo ...