咨詢電話:023-6276-4481
熱門文章
電 話:023-6276-4481
郵箱:broiling@qq.com
地址:重慶市南岸區(qū)亞太商谷6幢25-2
作為一個(gè).NET開發(fā)人員,懂Attribute的重要性,用.NET大師Jeffrey Richter的話就是“任何.NET Framework 開發(fā)人員都有必要對定制attribute有一個(gè)牢靠的掌握”,所以掌握Attitude,這是必須的!
什么是Attribute(特性)?和Property(屬性)是什么區(qū)別?
我們來看看MSDN中對特性的描述:
Attribute 類將預(yù)定義的系統(tǒng)信息或用戶定義的自定義信息與目標(biāo)元素相關(guān)聯(lián)。 目標(biāo)元素可以是程序集、類、構(gòu)造函數(shù)、委托、枚舉、事件、字段、接口、方法、可移植可執(zhí)行文件模塊、參數(shù)、屬性、返回值、結(jié)構(gòu)或其他特性。特性在您編譯代碼時(shí)被發(fā)送到元數(shù)據(jù)中,并可通過運(yùn)行時(shí)反射服務(wù)用于公共語言運(yùn)行時(shí)以及任何自定義工具或應(yīng)用程序。通俗地理解可以這么表述:你可以通過Attribute將一些額外信息加在一些目標(biāo)元素上(類,字段,接口等),程序編譯的時(shí)候就將這些額外的信息系列化程序集的元數(shù)據(jù)中,當(dāng)你運(yùn)行程序的時(shí)候可以通過反射技術(shù)從程序集元數(shù)據(jù)中讀取這些額外信息,并根據(jù)這些額外信息決定你程序的行為。
Attribute和Property有什么區(qū)別?其實(shí)這個(gè)問題是針對中文背景的開發(fā)者而言的,因?yàn)楹芏嘀形淖g本把Attribute和Property都翻譯成屬性,在這里為了區(qū)分,我們把Attribute翻譯為特性,Attribute和Property基本沒有什么瓜葛,因?yàn)樗鼈兪?NET中不同層面的東西,Property就是我們再熟悉不過的定義在類中的屬性,它屬于面向?qū)ο罄碚摲懂?,而Attribute是編程語言文法層面的東西,其定義在上面一段已經(jīng)描述。
你使用過.NET定義好的Attribute嗎?
在.NET的基礎(chǔ)類庫中提供了很多定制好的Attribute供開發(fā)人員使用,這些定制的Attribute目的的方便開發(fā)者在代碼中表達(dá)他們的意圖。如下面三個(gè)Attribute類都是C#編譯器能夠理解的特性類:
Obsolete:這個(gè)屬性用來標(biāo)記不再使用的程序?qū)嶓w(如類或方法),每次使用標(biāo)記為過時(shí)的實(shí)體時(shí),會(huì)設(shè)設(shè)定此特性的方法,產(chǎn)生警告或錯(cuò)誤。
Conditional:該特性可以標(biāo)示出某種環(huán)境設(shè)置下某個(gè)方法是否應(yīng)該被調(diào)用。
Serializable:指示一個(gè)類可以序列化。
下面以O(shè)bsolete特性的使用為例,說明Attribute是如何應(yīng)用它的目標(biāo)元素的。
namespace AttributeDemo
{
class Program
{
static void Main(string[] args)
{
MyClass myclass = new MyClass();
myclass.OldMethod();
Console.ReadKey();
}
}
public class MyClass
{
[Obsolete("這是一個(gè)舊的方法,請調(diào)用新的方法NewMethod")]
public void OldMethod()
{
Console.WriteLine("這是舊方法");
}
public void NewMethod()
{
Console.WriteLine("這是新方法");
}
}
}
調(diào)試這段程序的時(shí)候會(huì)發(fā)出警告信息,如下圖所示:
像Obsolete這樣的定制特性,編譯器能夠做出相應(yīng)處理,如在使用標(biāo)記了Obsolete特性的方法時(shí)會(huì)發(fā)出警告信息,但如果我們自己定制的Attribute時(shí),編譯器會(huì)做什么處理呢。下面我們自己定義一個(gè)Attribute。
我也來定義一個(gè)Attribute
為了符合“公共語言規(guī)范”(CLS),定制Attribute必須直接或間接從公共抽象類System.Attribute派生。所以我們前面提到Obsolete、Conditional和Serializable都是派生于Attribute。這里需要說明下的是自定制的Attribute的命名規(guī)范,其規(guī)則是“特性名+Attribute”,也就是我們自定制必須以Attribute為后綴,那么我們上面提到的三個(gè)特性都沒有Attribute為后綴的呢,原來定義它們的時(shí)候都是有Attribute后綴的,如Obsolete是ObsoleteAttribute,只是我們將一個(gè)特性應(yīng)用于某個(gè)目標(biāo)元素時(shí)可以將Attribute這個(gè)后綴去掉,因?yàn)榫幾g器會(huì)先查找沒有Attribute后綴的特性,如果沒有找到,則會(huì)查找加了Attribute后綴的特性名稱。
System.Attribute類的構(gòu)造器被protected修飾,說明它不能自己實(shí)例化,只能被它的派生類調(diào)用。它有三個(gè)重要的靜態(tài)方法,如下:
方法名稱 說明
GetCustomAttributes 有多個(gè)重載,返回作用于目標(biāo)的Attribute類實(shí)例的數(shù)組,也就是返回的類型是Attribute[]
GetCustomAttribute 有多個(gè)重載,返回作用于目標(biāo)的Attribute類的一個(gè)實(shí)例,如果目標(biāo)沒有應(yīng)用任何的Attribute則返回null,如果目標(biāo)應(yīng)用了指定的Attribute的多個(gè)實(shí)例,就拋出一個(gè)System.Reflection.AmbiguousMatchException異常。
IsDefined 如果至少有一個(gè)指定的Attribute派生類實(shí)例作用于目標(biāo),就返回true,否則返回false。這個(gè)方法效率很高,因?yàn)樗粯?gòu)建Attribute的實(shí)例,前面的兩個(gè)方法返回都是Attribute實(shí)例,也就是需要從元數(shù)據(jù)中獲取信息來構(gòu)建實(shí)例,耗費(fèi)性能多
通常檢查一個(gè)目標(biāo)元素是否被應(yīng)用了某個(gè)Attribute時(shí),就調(diào)用System.Attribute.IsDefined方法,因?yàn)樗男阅鼙菺etCustomAttributes和GetCustomAttribute要高,如果需要返回Attribute的實(shí)例,則調(diào)用GetCustomAttributes或GetCustomAttribute方法。調(diào)用這三個(gè)方法都會(huì)掃描托管模塊的元數(shù)據(jù)(因?yàn)锳ttribute是在編譯的時(shí)候保存在托管模塊的元數(shù)據(jù)上的),執(zhí)行字符串比較來定義指定的Attribute類。這樣的操作對時(shí)間性能消耗大,如果需要反復(fù)調(diào)用這些方法,可以緩存這些方法的調(diào)用結(jié)果,也就是把實(shí)例保存在全局變量中,不需要每次都掃描和構(gòu)造實(shí)例。
除了System.Attribute類提供的上面的三個(gè)靜態(tài)方法可以檢查目標(biāo)元素應(yīng)用Attribute的情況外,System.Reflection命名空間定義的一些類也允許你檢查一個(gè)模塊的元數(shù)據(jù)的內(nèi)容,這些類包括Assembly,Module,ParameterInfo,MemberInfo,Type,MethodInfo,ConstrucorInfo,F(xiàn)ieldInfo,EventInfo,PropertyInfo等,它們都提供了GetCustomAttributes和IsDefined方法。這些類GetCustomAttributes返回的類型是Object[],而System.Attribute類GetCustomAttributes方法返回的類型是Attribute[]。
下面將分別使用System.Attribute和System.Reflection.Type各自提供的GetCustomAttributes方法獲取Attribute實(shí)例提供示例代碼,以讓您有一個(gè)更加直觀的認(rèn)識(shí)。
定義一個(gè)Attribute
public class MyMsgAttribute:Attribute
{
public string Msg { get; set; }
public MyMsgAttribute(string msg)
{
Msg = msg;
}
}
定義一個(gè)類,使自定制的MyMsgAttribute類能夠應(yīng)用在這個(gè)類上,如下:
[MyMsgAttribute("我的自定義Attribute")]
public class MyClass
{
}
使用System.Reflection.Type提供的GetCustomAttributes方法獲取MyMsgAttribute類的實(shí)例,代碼如下:
var attributes = typeof(MyClass).GetCustomAttributes(typeof(MyMsgAttribute), true);
MyMsgAttribute myAttribute = attributes[0] as MyMsgAttribute;
if (myAttribute != null)
{
Console.WriteLine(myAttribute.Msg);
}
使用System.Attribute提供的GetCustomAttributes方法獲取MyMsgAttribute類的實(shí)例,代碼如下:
var attributes2 = Attribute.GetCustomAttributes(typeof(MyClass));
MyMsgAttribute myAttribute2 = (MyMsgAttribute)attributes2[0];
Console.WriteLine(myAttribute2.Msg);
上面兩段代碼輸出的結(jié)果都是Msg是屬性值——“我的自定義Attribute”。
上一篇
下一篇