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