[C#]Attribute特性(2)——方法的特性及特性参数
?上篇博文[C#]Attribute特性介紹了特性的定義,類的特性,字段的特性,這篇博文將介紹方法的特性及特性參數(shù)相關(guān)概念。
3.方法的特性?
????? 之所以將這部分單列出來(lái)進(jìn)行討論,是因?yàn)閷?duì)方法的特性查詢的反射代碼不同于對(duì)類的特性查詢的反射代碼。在這個(gè)例子里,我們將使用一個(gè)特性用來(lái)定義一種可進(jìn)行事務(wù)處理的方法。???
1 public class TransactionableAttribute : Attribute 2 { 3 public TransactionableAttribute() { } 4 } 1 public class TestClass 2 { 3 [Transactionable] 4 public void Foo() 5 { } 6 public void Bar() 7 { } 8 [Transactionable] 9 public void Baz() 10 { } 11 } 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Type type = typeof(TestClass); 6 foreach (MethodInfo method in type.GetMethods()) 7 { 8 foreach (Attribute attr in method.GetCustomAttributes()) 9 { 10 if (attr is TransactionableAttribute) 11 { 12 Console.WriteLine("{0} is transactionable.", method.Name); 13 } 14 } 15 } 16 Console.Read(); 17 } 18 }??? 代碼輸出結(jié)果為:
????
????? 在這個(gè)特殊的例子,僅僅憑借TransactionableAttribute就可以讓代碼知道具有這種特性的方法可以參與事務(wù)處理。這也是為什么在這里只有一個(gè)簡(jiǎn)單的、不帶參數(shù)的構(gòu)造函數(shù),而沒有其他成員。然后TestClass定義三種方法:Foo方法、Bar方法和Baz方法;其中Foo方法和Baz方法方法被定義為具有處理事務(wù)能力的方法。請(qǐng)注意您附加一個(gè)帶構(gòu)造函數(shù)的特性時(shí),如果這個(gè)構(gòu)造函數(shù)不帶參數(shù),您就不需要把左括號(hào)和右括號(hào)包括進(jìn)去了。
???? ?現(xiàn)在讓我們看看這個(gè)程序當(dāng)中指的關(guān)注的部分,看看怎樣通過(guò)方法的特性來(lái)查詢類的方法。我們開始先用typeof來(lái)獲得TestClass類的System.Type對(duì)象。
1 Type type = typeof(TestClass);?????? 然后我們使用Type.GetMethods方法來(lái)得到一個(gè)MethodInfo對(duì)象數(shù)組。每一個(gè)這樣的對(duì)象包括TestClass類的一個(gè)方法信息。我們用foreach語(yǔ)句來(lái)循環(huán)處理我們的每一個(gè)方法。
1 foreach (MethodInfo method in type.GetMethods())??? 現(xiàn)在我們有一個(gè)MethodInfo對(duì)象,我們就可以使用MethodInfo.GetCustomAttributes()方法來(lái)得到所有的用戶創(chuàng)建的方法特性。我們還是使用foreach語(yǔ)句來(lái)循環(huán)處理返回的對(duì)象數(shù)組。
1 foreach (Attribute attr in method.GetCustomAttributes())???????在代碼的這個(gè)地方,我們的方法有了特性?,F(xiàn)在,通過(guò)使用is操作符,我們來(lái)判斷一個(gè)特性是不是一個(gè)TransactionableAttribute,如果他是,就打印出這個(gè)方法的名字。
1 if (attr is TransactionableAttribute) 2 { 3 Console.WriteLine("{0} is transactionable.", method.Name); 4 }特性的參數(shù)
????? 在上面的例子中,通過(guò)構(gòu)造函數(shù)我們討論了附加特性的使用?,F(xiàn)在我們要來(lái)看看在前面沒有談到的特性的構(gòu)造函數(shù)的一些方面。
定位參數(shù)和命名參數(shù)
????? 在上一篇博文字段的特性的例子中,您看到一個(gè)名為RefistryKeyAttribute的特性。它的構(gòu)造函數(shù)形式如下:
1 public RegistryKeyAttribute(RegistryHives Hive, string valueName)????? 在這個(gè)構(gòu)造函數(shù)聲明之后,通過(guò)如下這種形式特性就附加給了一個(gè)字段:
1 [RegistryKey(RegistryHives. HKEY_CURRENT_USER,"Foo")] 2 public string Foo;?????? 到此為止,這些都很容易理解。這個(gè)構(gòu)造函數(shù)有兩個(gè)參數(shù),這兩個(gè)參數(shù)都是在把一個(gè)特性附加給一個(gè)字段時(shí)用到的。不過(guò),我們可以讓這種編程更簡(jiǎn)單。如果這個(gè)參數(shù)大多數(shù)時(shí)候都不變,那為什么每次都要讓使用這個(gè)類的用戶再費(fèi)勁地輸入這些參數(shù)呢?我們可以使用定位參數(shù)(position parameter)和命名參數(shù)來(lái)給這些參數(shù)設(shè)置默認(rèn)值。
???? 定位參數(shù)是用在構(gòu)造函數(shù)中的參數(shù)。在每次使用特性時(shí)它們是必須的參數(shù),并且要必須指明這些參數(shù)。在上面的RegistryKeyAttribute例子中,Hive和ValueName都是定位參數(shù)。命名參數(shù)在特性的構(gòu)造函數(shù)中實(shí)際上并沒有定義,更確切地說(shuō),它們是非靜態(tài)的字段和屬性。因此,在一個(gè)特性被實(shí)例化時(shí),命名參數(shù)讓客戶端能夠設(shè)置這個(gè)特性的字段和屬性,而不必讓您為客戶端要設(shè)置的每一種字段和屬性的可能的組合而創(chuàng)建構(gòu)造函數(shù)。
???? 每一個(gè)公共的構(gòu)造函數(shù)都可以定義一系列的定位參數(shù),就像所有類型的類一樣。但是,對(duì)于特性來(lái)說(shuō),一旦它的定位參數(shù)被確定,用戶就可以使用FieldOrPropertyName=Value來(lái)對(duì)某個(gè)字段或?qū)傩赃M(jìn)行引用。下面我們通過(guò)對(duì)特性RegistryKeyAttribute的修改來(lái)解釋一下這種情況。在這個(gè)例子里,我們?nèi)egistryKeyAttribute.ValueName作為一個(gè)定位參數(shù),而RegistryKeyAttribute.Hive就成了可選的命名參數(shù)。接下來(lái),問題就是“您怎樣才能把一些參數(shù)定義為命名參數(shù)?”因?yàn)橹挥卸ㄎ粎?shù)——即必需性的——參數(shù)才包括在構(gòu)造函數(shù)的定義中,因此我們只需簡(jiǎn)單地把這個(gè)可選參數(shù)從構(gòu)造函數(shù)的定義中刪除即可。然后用戶就可以引用如下部分作為命名參數(shù):非只讀、靜態(tài)或常量的任何字段,或包括設(shè)置存取器方法或非靜態(tài)的setter的任何屬性。因此,為了使RegistryKeyAttribute.Hive成為一個(gè)命名參數(shù),我們要把它從構(gòu)造函數(shù)的定義中刪除,因?yàn)樗鳛橐粋€(gè)公共的讀/寫屬性已經(jīng)存在了。
public RegistryKeyAttribute(string valueName)???? 用戶現(xiàn)在就可以用下面的任一種方法來(lái)附加特性了:
1 [RegistryKey(“Foo”)] 2 [RegistryKey(“Foo”,Hive=RegistryHives.HKEY_LOCAL_MACHINE)]????? 采用這種方式具有很好的靈活性,您既可以使用字段的默認(rèn)值,同時(shí),又可以讓用戶能夠在需要的時(shí)候用其他值覆蓋原來(lái)的默認(rèn)值。但是要記住:如果用戶沒有設(shè)置RegistryKeyAttribute.Hive字段的值,我們?cè)鯓觼?lái)默認(rèn)它?您也許會(huì)想到,“哦,我們來(lái)檢查一下看它是不是在構(gòu)造函數(shù)中設(shè)置了?!钡?#xff0c;問題是RegistryKeyAttribute.Hive是一個(gè)enum型的,它的底層數(shù)據(jù)類型是int型——它是一個(gè)數(shù)值。這就意味著在定義時(shí)編譯器已經(jīng)把它初始化為0了!如果我們測(cè)試一下構(gòu)造函數(shù)中RegistryKeyAttribute.Hive的值就會(huì)發(fā)現(xiàn)它等于0,我們不知道,是由調(diào)用程序通過(guò)命名參數(shù)設(shè)置的那個(gè)值,還是由編譯器在編譯時(shí),因?yàn)樗且粋€(gè)數(shù)值型才給它設(shè)置了該值。不幸的是,現(xiàn)在能解決這個(gè)問題的唯一的途徑是改變這段代碼,讓它的值為0時(shí)無(wú)效。這可以通過(guò)如下改變RegistryHives enum的方式實(shí)現(xiàn):?
1 public enum RegistryHives 2 { 3 HKEY_CLASSES_ROOT=1, 4 HKEY_CURRENT_USER, 5 HKEY_LOCAL_MACHINE, 6 HKEY_USERS, 7 HKEY_CURRENT_CONFIG 8 }????? 現(xiàn)在我們知道,使RegistryKeyAttribute.Hive為0的唯一途徑是編譯器把它初始化為0,并且用戶沒有通過(guò)一個(gè)命名參數(shù)來(lái)覆蓋它的初值。我們可以用類似下面的代碼來(lái)將其初始化:
1 public RegistryKeyAttribute(string valueName) 2 { 3 this.valueName = valueName; 4 if (this.Hive == 0) 5 { 6 this.hive = RegistryHives.HKEY_CURRENT_USER; 7 } 8 }使用命名參數(shù)時(shí)的常見錯(cuò)誤
??????當(dāng)您使用命名參數(shù)時(shí),您必須首先要指定定位參數(shù)。之后,由于命名參數(shù)是放在字段名或?qū)傩灾暗?#xff0c;因此命名參數(shù)之間沒有先后順序。下面的例子將導(dǎo)致一個(gè)編譯錯(cuò)誤。
1 //This is an error because postional parameters can't follow 2 //named parameters 3 [RegistryKey(Hive=RegistryHives.HKEY_LOCAL_MACHINE, "Foo")]????? 另外,您不能命名定位參數(shù)。編譯器在編譯特性的使用時(shí),它會(huì)試著先去解析那些命名參數(shù)。然后再試著根據(jù)方法特性去解析剩下的——定位參數(shù)值。本段下面的代碼無(wú)法通過(guò)編譯,因?yàn)樵谝馕龅膮?shù)當(dāng)中必須半酣至少一個(gè)定位參數(shù),如果全部都是命名參數(shù),就會(huì)出現(xiàn)提示“No overload for method 'Registrykey Attribute 'takes ' O' arguments”(RegistrykeyAttribute方法沒有參數(shù)值,無(wú)法進(jìn)行重載)。
1 [RegistryKey(ValueName="Foo",Hive=RegistryHives.HKEY_LOCAL_MACHINE)]???? 最后,命名參數(shù)可以是任何公共的、可存取的字段或?qū)傩浴╯etter方法——只要不是靜態(tài)的或常量即可。
有效的特性參數(shù)類型
????? 特性類的定位參數(shù)和命名參數(shù)的類型僅限于特性參數(shù)類型,這些包括:
- bool,byte,char,double,float,int,long,short,string
- System.Type
- object
- enum類型,前提是它或任何有它嵌套在里面的類型必須是公共的可存取類型——就像在那個(gè)使用RegistryHives枚舉的例子中一樣。
- 由上述的任何類型組成的一維數(shù)組。
???? 因?yàn)橛行У膮?shù)類型僅局限于上述列出來(lái)的類型,因此您不能把一個(gè)像類那樣的數(shù)據(jù)結(jié)構(gòu)傳遞給特性構(gòu)造函數(shù)作為參數(shù)。這種限制很有意義,因?yàn)樘匦允窃诔绦蛟O(shè)計(jì)時(shí)附加上的,此時(shí)您并沒有這個(gè)類(對(duì)象)的實(shí)例化的實(shí)例。使用上面列出來(lái)的這些有效類型,您就可以在程序設(shè)計(jì)時(shí)把他們的值固定下來(lái),就是為什么能使用他們的原因。
結(jié)語(yǔ)
???? 方法的特性和特性參數(shù)就介紹到這里,您如果想了解更多請(qǐng)參考《c#技術(shù)內(nèi)幕》這本書,本文也是摘自這本書,記錄在此,方便回顧,也分享給大家,希望能對(duì)您有所幫助。下篇將學(xué)習(xí)AttributeUsage特性和特性標(biāo)識(shí)符。敬請(qǐng)期待......
?
?
?
| 博客地址: | http://www.cnblogs.com/wolf-sun/ |
| 博客版權(quán): | 本文以學(xué)習(xí)、研究和分享為主,歡迎轉(zhuǎn)載,但必須在文章頁(yè)面明顯位置給出原文連接。 如果文中有不妥或者錯(cuò)誤的地方還望高手的你指出,以免誤人子弟。如果覺得本文對(duì)你有所幫助不如【推薦】一下!如果你有更好的建議,不如留言一起討論,共同進(jìn)步! 再次感謝您耐心的讀完本篇文章。 轉(zhuǎn)載:http://www.cnblogs.com/wolf-sun/p/3392765.html |
總結(jié)
以上是生活随笔為你收集整理的[C#]Attribute特性(2)——方法的特性及特性参数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 唐雎不辱使命1,2段原文翻译
- 下一篇: asp.net(c#)将彩色图片变灰阶图