元數據,就是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