C# 特性(Attribute)学习

  特性(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'

  开发定制特性(custom attributes)

  现在让我们来看看如何开发我们自己的特性。

  首先我们要从System.Attribute派生出我们自己的特性类(一个从System.Attribute抽象类继承而来的类,不管是直接还是间接继承,都会成为一个特性类。特性类的声明定义了一种可以被放置在声明之上新的特性)。

  using System;

  public class HelpAttribute : Attribute

  {

  }

  不管你是否相信,我们已经建立了一个定制特性,现在我们可以用它来装饰现有的类就好像上面我们使用Obsolete attribute一样。

  [Help()]

  public class AnyClass

  {

  }

  注意:对一个特性类名使用Attribute后缀是一个惯例。然而,当我们把特性添加到一个程序实体,是否包括Attribute后缀是我们的自由。编译器会首先在System.Attribute的派生类中查找被添加的特性类。如果没有找到,那么编译器会添加Attribute后缀继续查找。

  到目前为止,这个特性还没有起到什么作用。下面我们来添加些东西给它使它更有用些。

  using System;

  public class HelpAttribute : Attribute

  {

  public HelpAttribute(String Descrition_in)

  {

  this.description = Description_in;

  }

  protected String description;

  public String Description

  {

  get

  {

  return this.description;

  }

  }

  }

  [Help("this is a do-nothing class")]

  public class AnyClass

  {

  }

  在上面的例子中,我们给HelpAttribute特性类添加了一个属性并且在后续的部分中我们会在运行时环境中查寻它。

  定义或控制特性的使用

  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

  {

  }

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

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]

  [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类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述了一个定制特性如和被使用。

  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, 下面考虑一下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

  {

  }

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

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]

  [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]

  [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。

 

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

时间: 2024-10-06 06:05:43

C# 特性(Attribute)学习的相关文章

温故而知新:c#中的特性(attribute)

特性(Attribute)是微软在.Net中自创的一种新技术,对于很多初学者来讲,特性一直是一块难啃的骨头. 既然弄不懂,那我们就暂时绕过它吧,回想一下我们在写代码时通常都要求写注释,为了是让别人或自己以后能看得懂,但是这个注释是写给"人"看的,突发奇想一下:我们能不能写出一种注释,给c#编译器看,比如我们在某些代码上打个标记,让编译器看到这些标记后,做出不同的反应? 其实...这就是特性,比如我们定义一个常规的类 public class Product { public strin

C#特性Attribute的实际应用之:代码统计分析

日常工作中,需要为程序集提供统计分析: 1:程序集方法数: 2:开发人员数目及各自所开发或REVIEW的方法数: 3:测试中,被标注有BUG的数目: 4:直接查看方法的IL代码: 鉴于以上统计的需要,特开发本EXE. 1:关于特性Attribute的知识补充 "Attribute是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标".它的作用是为它们的修饰目标追加上一些额外的信息--比如"这个类是我写的"或者"这个函数以前出

C#特性Attribute的“.NET研究”实际应用之:代码统计分析

日常工作中,需要为程序集提供统计分析: 1:程序集方法数: 2:开发人员数目及各自所开发或REVIEW的方法数: 3:测试中,被标注有BUG的数目: 4:直接查看方法的IL代码: 鉴于以上统计的需要,特开发本EXE. 1:关于特性Attribute的知识补充 "Attribute是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标".它的作用是为它们的修饰目标追加上一些额外的信息--比如"这个类是我写的"或者"这个函数以前出

一起谈.NET技术,C#特性Attribute的实际应用之:代码统计分析

日常工作中,需要为程序集提供统计分析: 1:程序集方法数: 2:开发人员数目及各自所开发或REVIEW的方法数: 3:测试中,被标注有BUG的数目: 4:直接查看方法的IL代码: 鉴于以上统计的需要,特开发本EXE. 1:关于特性Attribute的知识补充 "Attribute是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标".它的作用是为它们的修饰目标追加上一些额外的信息--比如"这个类是我写的"或者"这个函数以前出

利用特性(Attribute)对实体类进行验证

对于XML的内容,我这边的处理方式是将它反序列化成实体对象,毕竟操作一 个实体对象比一大堆的XPath强多了. .net framework自带的XML序列化和反序列化类 System.Xml.Serialization.XmlSerializer由于内部实现过于复杂,导致性能不 佳.我这边自己实现了一个XML反序列化类,性能虽好但比较有针对性,所以今 天还是以.net framework自带的XML反序列化类作为示范. 比如说一个XML的内容是这样: <? xml version = "

结合C++11新特性来学习C++中lambda表达式的用法_C 语言

在 C++ 11 中,lambda 表达式(通常称为 "lambda")是一种在被调用的位置或作为参数传递给函数的位置定义匿名函数对象的简便方法. Lambda 通常用于封装传递给算法或异步方法的少量代码行. 本文定义了 lambda 是什么,将 lambda 与其他编程技术进行比较,描述其优点,并提供一个基本示例.Lambda 表达式的各部分ISO C++ 标准展示了作为第三个参数传递给 std::sort() 函数的简单 lambda: #include <algorithm

JDK5新特性---注解学习笔记(一)

1.注解(也被称为元数据):为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据.   2.  javaSE内置了3种标准注解: @Override       表示当前的方法定义将覆盖超类中的方法.如果你不小心拼写错误,或者方法签名对不上被覆盖的方法,编译器就会发出错误的提示. @Deprecated   如果程序员使用了注解为它的元素,那么编译器会发出警告信息. @SuppressWarnings   关闭不当的编译器警告信息.         在我们

Attribute/特性心得随笔_实用技巧

复制代码 代码如下: <p>/*</p><p>*特性</p><p>*/</p> 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary> /// DisAttribute 的摘要说明 /// </summary> public class DisAtt

关于C# 中的Attribute 特性

Attribute与Property 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标. 简单的说,Attribute就是一种"附着物" -- 就像牡蛎吸附在船底或礁石上一样. 这些附着物的作用是为它们的附着体追加上一些额外的信息(这些信息就保存在附着物的体内)-- 比如&qu