C# 特性详解

C# 特性详解 

1、什么是特性

     1)属性与特性的区别

         属性(Property):属性是面向对象思想里所说的封装在类里面的数据字段,Get,Set方法。

         特性(Attribute):  官方解释:特性是给指定的某一声明的一则附加的声明性信息。 允许类似关键字的描述声明。它对程序中的元素进行标注,如类型、字段、方法、属性等。从.net角度看,特性是一种 类,这些类继承于System.Attribute类,用于对类、属性、方法、事件等进行描述,主要用在反射中。但从面向对象的级别看,其实Attribute是类型级别的,而不是对象级别。

         Attributes和.net文件的元素据保存在一起,可以用来向运行时描述你的代码,或者在程序运行的时候影响程序的行为。

2、特性的应用

    (1).net中特性用来处理多种问题,比如序列化、程序的安全特性、防止即时编译器对程序代码进行优化从而代码容易调试等等。

     定植特性的本质上是一个类的元素上去添加附加信息,并在运行其通过反射得到该附加信息(在使用数据实体对象时经常用到)

    (2)Attribute 作为编译器的指令时的应用

         Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用

         DllImport: 用来标记费.net的函数,表明该方法在一个外部的DLL中定义。

         Obsolete: 这个属性用来标记当前的方法已经废弃,不再使用

       注:Attribute是一个类,因此DllImport也是一个类,Attribute类是在编译的时候实例化,而不是像通常那样在运行时实例化。

         CLSCompliant: 保证整个程序集代码遵守CLS,否则编译将报错。

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

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

复制代码
 1 using System; 
 2 public class AnyClass 
 3 { 
 4     [Obsolete("Don't use Old method, use New method", true)] 
 5     static void Old( ) { }  
 6     static void New( ) { } 
 7     public static void Main( ) 
 8     { 
 9         Old( ); 
10     } 
11 } 
复制代码

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

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

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

    开发定制特性(custom attributes)

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

1 using System; 
2 public class HelpAttribute : Attribute 
3 { 
4 } 

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

1 [Help()] 
2 public class AnyClass 
3 { 
4 } 

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

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

复制代码
 1 using System; 
 2 public class HelpAttribute : Attribute 
 3 { 
 4     public HelpAttribute(String Descrition_in) 
 5     { 
 6         this.description = Description_in; 
 7     } 
 8     protected String description; 
 9     public String Description 
10     { 
11         get 
12         { 
13             return this.description; 
14         } 
15     } 
16 } 
17 [Help("this is a do-nothing class")] 
18 public class AnyClass 
19 { 
20 } 
复制代码

   

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

 

    定义或控制特性的使用

    AttributeUsage类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述了一个定制特性如和被使用。 
    AttributeUsage有三个属性,我们可以把它放置在定制属性前面。第一个属性是: 

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


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

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

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

复制代码
 1 using System; 
 2 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 
 3 public class HelpAttribute : Attribute 
 4 { 
 5     public HelpAttribute(String Description_in) 
 6     { 
 7         this.description = Description_in; 
 8     } 
 9     protected String description; 
10     public String Description 
11     { 
12         get 
13         { 
14             return this.description; 
15         } 
16     } 
17 } 
复制代码

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

复制代码
1 [Help("this is a do-nothing class")] 
2 public class AnyClass 
3 { 
4     [Help("this is a do-nothing method")] //error 
5     public void AnyMethod() 
6     { 
7     } 
8 } 
复制代码

    编译器报告错误如下:

   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。它规定了特性不能被重复放置多次。 

复制代码
1 [Help("this is a do-nothing class")] 
2 [Help("it contains a do-nothing method")] 
3 public class AnyClass 
4 { 
5     [Help("this is a do-nothing method")] //error 
6     public void AnyMethod() 
7     { 
8     } 
9 } 
复制代码

    它产生了一个编译期错误。 
    AnyClass.cs: Duplicate 'Help' attribute

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

复制代码
1 [Help("BaseClass")] 
2 public class Base 
3 { 
4 } 
5 public class Derive : Base 
6 { 
7 } 
复制代码

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

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。

    第三种情况:

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

复制代码
1 [Help("BaseClass")] 
2 public class Base 
3 { 
4 } 
5 [Help("DeriveClass")] 
6 public class Derive : Base 
7 { 
8 } 
复制代码

 

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

    第四种情况:

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

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

 

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

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Foxalien/archive/2009/12/05/4946672.aspx

猜你喜欢

转载自blog.csdn.net/sbayje/article/details/8857958