C#  特性的学习(一)

来源:互联网 发布:网络摄像监控 编辑:程序博客网 时间:2024/06/11 18:48

      元数据,就是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 classMyselfAttribute:System.Attribute 

自定义特定:

//限定特性类的应用范围
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Field,AllowMultiple = true, Inherited = false)]
//定制MsgAttribute特性类,继承于Attribute
public class ClassMsgAttribute : Attribute
{
   //定义_msg字段和Msg属性//Msg属性用于读写msg字段
    string_msg;
    publicstring Msg { get { return _msg; } set { _msg = value; } }
    publicClassMsgAttribute() { }
   //重载构造函数接收一个参数,赋值给_msg字段
    publicClassMsgAttribute(string s) { _msg = s; } 
}

调用:

//在Person类上标记ClassMsg特性
[ClassMsg(Msg = "这是关于人的姓名信息的类")]
class Person
{
   //在_name字段上应用ClassMsg特性
   [ClassMsg("这是存储姓名的字段")]
    string_name;
   //以下特性无法应用,因为MsgAttribute定义的特性只能用于类和字段
   //[ClassMsg("这是读写姓名字段的属性")]
    publicstring Name { get { return _name; } set { _name = value; } }
}

主函数的情况

  static void Main(string[] args)
    {
       //获取Person类的Type对象tp
       Type tp = Type.GetType("Person");
       //获取tp对象的特性数组,并将数组赋值给MyAtts
       object[] MyAtts = tp.GetCustomAttributes(false);
       //遍历并输出MyAtts数组子项的Msg属性
       foreach (ClassMsgAttribute m in MyAtts)
       {
           Console.WriteLine("Person类的特性:{0}", m.Msg);
       }

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

 

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

usingSystem;

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

{

  //...

}

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

[Help()]

public classAnyClass

{

   //...

}

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

 

定义或控制特性的使用

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

 

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

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

 usingSystem;
   [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 onthis 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-nothingclass")]
   [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。


转自:http://blog.csdn.net/helloguonan/article/details/5912032

0 0