C#特性学习笔记

来源:互联网 发布:长沙网络公关 编辑:程序博客网 时间:2024/06/18 11:22

元数据,就是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,否则编译将报错。

 

 3、自定义特性

      使用AttributeUsage,来控制如何应用新定义的特性

     [AttributeUsageAttribute(AttributeTargets.All  可以应用到任何元素

      ,AllowMultiple=true, 允许应用多次,我们的定值特性能否被重复放在同一个程序实体前多次。

      ,Inherited=false,不继承到派生

        )]

     特性也是一个类,必须继承于System.Attribute类,命名规范为“类名”+Attribute。不管是直接还是间接继承,都会成为一个特性类,特性类的声明定义了一种可以放置在声明之上新的特性。

 

     public class MyselfAttribute:System.Attribute

 

自定义特定:

 

[c-sharp] view plaincopy
  1. //限定特性类的应用范围  
  2. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]  
  3. //定制MsgAttribute特性类,继承于Attribute  
  4. public class ClassMsgAttribute : Attribute  
  5. {  
  6.     //定义_msg字段和Msg属性//Msg属性用于读写msg字段  
  7.     string _msg;  
  8.     public string Msg { get { return _msg; } set { _msg = value; } }  
  9.     public ClassMsgAttribute() { }  
  10.     //重载构造函数接收一个参数,赋值给_msg字段  
  11.     public ClassMsgAttribute(string s) { _msg = s; }   
  12. }  

 

调用:

[c-sharp] view plaincopy
  1. //在Person类上标记ClassMsg特性  
  2. [ClassMsg(Msg = "这是关于人的姓名信息的类")]  
  3. class Person  
  4. {  
  5.     //在_name字段上应用ClassMsg特性  
  6.     [ClassMsg("这是存储姓名的字段")]  
  7.     string _name;  
  8.     //以下特性无法应用,因为MsgAttribute定义的特性只能用于类和字段  
  9.     //[ClassMsg("这是读写姓名字段的属性")]  
  10.     public string Name { get { return _name; } set { _name = value; } }  
  11. }  

 

主函数的情况

[c-sharp] view plaincopy
  1. static void Main(string[] args)  
  2.   {  
  3.       //获取Person类的Type对象tp  
  4.       Type tp = Type.GetType("Person");  
  5.       //获取tp对象的特性数组,并将数组赋值给MyAtts  
  6.       object[] MyAtts = tp.GetCustomAttributes(false);  
  7.       //遍历并输出MyAtts数组子项的Msg属性  
  8.       foreach (ClassMsgAttribute m in MyAtts)  
  9.       {   
  10.           Console.WriteLine("Person类的特性:{0}", m.Msg);   
  11.       }  

GetCustomAttributes用于获取程序集的特性,也就是这个程序集合中包含了多少个特性

 

继续来一个简单的例子来说明定制特性:

using System;

public class HelpAttribute: Attribute  //定制特性相当于一个类

{

   //...

}

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

[Help()]

public class AnyClass

{

   //...

}

注意:对于一个特性类使用Attribute后缀是一个惯例。然而,如果不添加编译器会自动添加匹配。

 

定义或控制特性的使用

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

  

下面通过实例来探讨下AttributeUsage的三个属性

1)我们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。  

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

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

[c-sharp] view plaincopy
  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. }   
  9.   
  10. //编译器报告错误如下:     
  11.   
  12. AnyClass.cs: Attribute 'Help' is not valid on this declaration type.   
  13. 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。它规定了特性不能被重复放置多次。  

[c-sharp] view plaincopy
  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.   }   
  10.   
  11.   它产生了一个编译期错误。    
  12.   
  13.   AnyClass.cs: Duplicate 'Help' attribute    

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

[c-sharp] view plaincopy
  1. [Help("BaseClass")]   
  2. public class Base   
  3. {   
  4. }   
  5.   
  6. public class Derive : Base   
  7. {   
  8. }   
  9.   
  10. 这里会有四种可能的组合:    
  11.   
  12. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]   
  13. [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]   
  14. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]   
  15. [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。

0 0