41. C# -- 特性

 元數據,就是C#中封裝的一些類,沒法修改.類成員的特性被稱爲元數據中的註釋.html

一、什麼是特性c#

     1)屬性與特性的區別數組

         屬性(Property):屬性是面向對象思想裏所說的封裝在類裏面的數據字段,Get,Set方法。安全

         特性(Attribute):  官方解釋:特性是給指定的某一聲明的一則附加的聲明性信息。 容許相似關鍵字的描述聲明。它對程序中的元素進行標註,如類型、字段、方法、屬性等。從.net角度看,特性是一種 類,這些類繼承於System.Attribute類,用於對類、屬性、方法、事件等進行描述,主要用在反射中。但從面向對象的級別看,其實Attribute是類型級別的,而不是對象級別。網絡

         Attributes和.net文件的元素據保存在一塊兒,能夠用來向運行時描述你的代碼,或者在程序運行的時候影響程序的行爲。ide

二、特性的應用函數

    (1).net中特性用來處理多種問題,好比序列化、程序的安全特性、防止即時編譯器對程序代碼進行優化從而代碼容易調試等等。性能

     定植特性的本質上是一個類的元素上去添加附加信息,並在運行其經過反射獲得該附加信息(在使用數據實體對象時常常用到)學習

    (2)Attribute 做爲編譯器的指令時的應用優化

         Conditional:起條件編譯的做用,只有知足條件,才容許編譯器對它的代碼進行編譯。通常在程序調試的時候使用

         DllImport: 用來標記費.net的函數,代表該方法在一個外部的DLL中定義。

         Obsolete: 這個屬性用來標記當前的方法已經廢棄,再也不使用

       注:Attribute是一個類,所以DllImport也是一個類,Attribute類是在編譯的時候實例化,而不是像一般那樣在運行時實例化。

         CLSCompliant: 保證整個程序集代碼遵照CLS,不然編譯將報錯。

 

 三、自定義特性

      使用AttributeUsage,來控制如何應用新定義的特性

     [AttributeUsageAttribute(AttributeTargets.All  能夠應用到任何元素

      ,AllowMultiple=true, 容許應用屢次,咱們的定值特性可否被重複放在同一個程序實體前屢次。

      ,Inherited=false,不繼承到派生

        )]

     特性也是一個類,必須繼承於System.Attribute類,命名規範爲「類名」+Attribute。不論是直接仍是間接繼承,都會成爲一個特性類,特性類的聲明定義了一種能夠放置在聲明之上新的特性。


代碼以下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace CollectionsApplication
{
    //1. 自定義特定:
    //限定特性類的應用範圍  
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Field, AllowMultiple = true, Inherited = false)]  
    //定製MsgAttribute特性類,繼承於Attribute  
    public class ClassMsgAttribute : Attribute  
{
        //定義_msg字段和Msg屬性//Msg屬性用於讀寫msg字段  
        string _msg;  
        public string Msg { get { return _msg; } set { _msg = value; } }  
        public ClassMsgAttribute() { }  
        //重載構造函數接收一個參數,賦值給_msg字段  
        public ClassMsgAttribute(string s) { _msg = s; }   
}
    //2. 調用:
    //在Person類上標記ClassMsg特性
    [ClassMsg(Msg = "this is the class for  name attribute")]
    class Person
{
        //在_name字段上應用ClassMsg特性
        [ClassMsg("this is name attribute.")]
        string _name;
        //如下特性沒法應用,由於MsgAttribute定義的特性只能用於類和字段
        //[ClassMsg("這是讀寫姓名字段的屬性")]
        public string Name { get { return _name; } set { _name = value; } }
}
    public class Test
{
        //3. 主函數狀況:
        static void Main(string[] args)
{
            //獲取Person類的Type對象tp
            Type tp = typeof(Person);
            //獲取tp對象的特性數組,並將數組賦值給MyAtts
            object[] MyAtts = tp.GetCustomAttributes(true);
            //object[] MyAtts = typeof(Person).GetCustomAttributes(false);
            //遍歷並輸出MyAtts數組子項的Msg屬性
            foreach (ClassMsgAttribute m in MyAtts)
{
                Console.WriteLine("Class Person attribute:{0}", m.Msg);
}
            Console.ReadLine();
}
        //運行結果:
        //class person attribute:this is the class for name attribute
}
}

GetCustomAttributes用於獲取程序集的特性,也就是這個程序集合中包含了多少個特性

 

繼續來一個簡單的例子來講明定製特性:

using System;

public class HelpAttribute: Attribute  //定製特性至關於一個類

{

   //...

}

無論你是否相信,咱們上面已經創建了一個定製特性,如今咱們能夠用它來裝飾現有的類就好像咱們使用的Obsolete attribute同樣。

[Help()]

public class AnyClass

{

   //...

}

注意:對於一個特性類使用Attribute後綴是一個慣例。然而,若是不添加編譯器會自動添加匹配。

 

定義或控制特性的使用

AttributeUsage類是另一個預約義特性類,它幫助咱們控制咱們本身的定製特性的使用。它描述一個定製特性如何被使用。

  

下面經過實例來探討下AttributeUsage的三個屬性

1)咱們將會在剛纔的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(AttributeTargets.Class|AttributeTargets.Method)]
    class WahAttribute:System.Attribute
    {
        private string description;
        public string Description
        {
            get { return description; }
            set { description = value; }
        }
        private string author;
        public string Author
        {
            get { return author; }
            set { author = value; }
        }
        public WahAttribute(string desc)
        {
            this.description = desc;
        }
    }


運用特性類:

namespace attributeDemo
{
    public class Teacher
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private int age;
        public int Age
        {
            get { return age; }
            set { age = value; }
        }
        private string sex;
        public string Sex
        {
            get { return sex; }
            set { sex = value; }
        }
        //只有用戶名爲wah的才能夠調用此方法
        [Wah("this is my attribute test", Author = "wah", Description = "test")]
        public string getMessage()
        {
            return "好好學習,每天向上";
        }
        [Wah("this is with parameters test",Author="wanggaihui",Description="test with parameters")]
        public int Test(int a,int b)
        {
            return a+b;
        }
    }
}


處理特性類:

        private void button_Click(object sender, EventArgs e)
        {
            //獲得類型
            Type type = typeof(Teacher);
            //獲得此類型全部方法
            MethodInfo[] methods = type.GetMethods();
            foreach (MethodInfo method in methods)
            {
                //獲得此方法的全部特性
                object[] attributes = method.GetCustomAttributes(false);
                foreach (object o in attributes)
                {
                    //判斷是不是本身定義的特性
                    if (o.GetType() == typeof(WahAttribute))
                    {
                        //強轉取得值
                        WahAttribute waha = (WahAttribute)o;
                        this.listBox1.Items.Add("author=" + waha.Author);
                        this.listBox1.Items.Add("description=" + waha.Description);
                    }
                }
            }
        }

C#特性能夠應用於各類類型和成員。加在類前面的是類特性,加在方法前面的是方法特性。不管他們被用在哪裏,不管他們之間有什麼區別,特性的最主要的目的就是自描述。而且由於特性是能夠由本身定製的,而不只僅侷限於.net提供的那幾個現成的,所以給C#程序開發帶來了很大的靈活性。

 

咱們仍是借用生活中的例子來介紹C#的特性機制吧。

假設有一天你去坐飛機,你就必須提早去機場登機處換登機牌。登機牌就是一張紙,上面寫着哪趟航班、由哪裏飛往哪裏以及你的名字、座位號等等信息,其實,這就是特性。它不須要你生理上包含這些屬性(人類出現那會兒還沒飛機呢),就像上面的HumanBase類沒有IsSerializable這樣的屬性,特性只須要在類或方法須要的時候加上去就好了,就像你不老是在天上飛同樣。

 

 


拿到了登機牌,就意味着你能夠合法地登機起飛了。但此時你還不知道你要坐的飛機停在哪裏,不用擔憂,地勤人員會開車送你過去,可是他怎麼知道你是哪趟航班的呢?顯然仍是經過你手中的登機牌。因此,特性最大的特色就是自描述。

既然是起到描述的做用,那目的就是在於限定。就比如地勤不會把你隨便拉到一架飛機跟前就扔上去了事,由於標籤上的說明信息就是起到限定的做用,限定了目的地、乘客和航班,任何差錯都被視爲異常。若是前面的HumanBase不加上Serializable特性就不能在網絡上傳輸。

  

指定特性參數

若是找到這樣的構造函數,編譯器就會把指定的元數據傳送給程序集。若是找不到,就生成一個這樣的構造函數。若是找到一個這樣的構造函數,編譯器就會把指定的元數據傳送給程序集。若是找不到就生成一個編譯錯誤。如後面所述,反射會從程序集中讀取元數據,並實例化他們表示的特性類。所以,編譯器須要確保存在這樣的構造函數,才能在運行期間實例化指定的特性。

參考:https://msdn.microsoft.com/zh-cn/library/67ef8sbd(v=vs.80).aspx http://zhidao.baidu.com/link?url=FArDop5J7k64OP9APCOZRfRNJ-Y6QcAvI0Y5Dt-4bXh-lxhpImjC1ugmxAv6il9Pc-blnU9PPnsQLpZNr-575qhttp://blog.csdn.net/helloguonan/article/details/5912032 https://msdn.microsoft.com/zh-cn/library/z0w1kczw(v=vs.110).aspxhttp://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html

相關文章
相關標籤/搜索