深刻淺出Attribute (上)——Attribute初體驗

小序:

         注意:本次小序頗長並且沒什麼正事兒,建議你們直接跳到正文,以避免浪費寶貴時間:)
         積水潭橋旁的物美大賣場有兩層——B1B2B1賣電器和日用品(歸納起來講就是那些不能吃的——貓糧除外),B2是賣食品的,又分爲兩個區,南區是賣零食的,北區是賣蔬菜水果生肉熟肉的。之前轉的最多的是南區,購物車裏大包小包一堆零食還要再抱上兩大桶可樂,衣着整潔的時候偶爾還僞裝斯文給打扮入時的小MM讓個路、擠個眉弄個眼兒什麼的;如今基本上只在北區轉了,購物車裏全是折價蔬菜大米油鹽,天天都是褲衩背心、趿拉着拖鞋,常常是跟退休的大媽們混戰在一塊兒扒拉架豆角或者擗菜幫……
 
         ~~~逛超市最麻煩的倒不是買東西,而是排大長隊付款——尤爲是週末:p
不過,本週末晚上我但是遇見一猛人,PLMM。她先是從北區後場啓動,嘁哩喀喳裝了一堆菜到稱重處過秤,而後靈活地繞過乾貨區,而後在到達南北區的中線的時候來了個急停。左顧右盼幾秒鐘後,「啪、啪」裝了兩大包FB面以後便忽然啓動殺入了零食林立的南區中場——只見她矯健的身影在零食區的貨架間穿插自如、大搞S形機動,桑巴之態如入無人之境,幾乎overload的購物車在她腳下,不,是手中!左盤右帶、就像魔術師手中的道具同樣靈活。她打開一張紙,大概是要買的東西,從上到下掃描一遍後自信地點了下頭——看來是要買的東西已經買齊了,而後眯起眼睛、遠遠地望了一眼收銀臺,臉上略過一絲不易察覺的、邪邪的笑……
 
看!她加速了,加速了!!她已經衝過了飲料區,兩個顧客橫在過道出口、封住了她前進的道路。只見她又是一個急停,把車以90度角向左一推,而後再以90度角向右一轉——這是多麼流暢的普加喬夫眼鏡蛇機動!兩個顧客尚未反應過來,她已經殺出了飲料區,直奔收銀臺……
 
離收銀臺不足十碼了!眼看就有兩個顧客要卡在她前面交費了!怎麼辦!怎麼辦?!
她先是利用本身的速度優點殺到較近的一個顧客身旁,輕挑車頭,打算用假動做騙過這名顧客,讓這名顧客迫於壓力進入另外一付費通道。看!她成功了!!而這時,另外一名顧客立刻就要進入交費通道了——剎那間,她作出了另人難以想象的動做!她先是把車往左一帶,而後又往右一撥,雙手忽然發力腳下同時加速——人車分過!人車分過!!!哇噻!!她又成功了!!此時,她面前只有收銀員了!!面對收銀員她絲毫沒有遲疑、沒有猶豫、沒有任何放慢速度的意思——偉大的意大利左後衛!!!勝利是屬於你的!!!
 
~~~~~~~~~~~~~~
在警報響起的同時,收銀員穩穩地將車抱入懷中!
衝撞收銀員!超市管理員跑過來了,一邊跑一邊~~~好像是在掏牌兒~~~讓咱們看看他掏的是什麼牌兒……哇哦!紅牌,是紅牌!!
兩名保安走過來,準備把PLMM架出場外。超市管理員來到收銀員旁邊,察看收銀員有沒有受傷。
怎麼回事?!場上一陣騷亂!一名保安倒在了地上,痛苦地捂着胸口在地上打滾!這究竟是怎麼回事?讓咱們看一下超市監控錄像的慢動做回放……保安先是拉了一下MMT Shirt,被MM用手撥開,走了兩步以後,MM忽然衝回來用頭狠狠地頂在保安的胸口!保安凌空翻轉,重重摔在地上!——God!這究竟是怎麼回事?!保安到底對MM作了什麼,或者是說了什麼,以至MM出此狠招?!
……

正文:

         什麼是AttributeAttribute是幹什麼使的?AttributeProperty到底有什麼區別?……
長久以來,這些問題一直困擾着並不怎麼廣大的C#初學者。緣由大概有兩個,一是Attribute平時不怎麼經常使用(沒用慣怎麼可能經常使用嗎!)二是這個傢伙不太好翻譯——它與Property這個詞意義相近,都有「屬性」這個詞條(並且在HTML語言中,Attribute也的確與C#面向對象概念中的Property意思一致),所以不少譯者,特別是C#剛剛出來那陣子,拿捏很差應該怎麼翻譯,搞的C#初學者一遇到「屬性」就發懵、一遇到「Attribute」就發怵。如今狀況還算比較明朗了,Attribute通常譯做「特性」,Property仍然譯爲「屬性」。
         今天,先讓咱們來學習一下到底什麼是Attribute並體驗一下Attribute的威力,而後讓咱們完全澄清AttributeProperty之間的區別。

什麼是Attribute

         大多數書籍都喜歡講——「Attribute是一種可由用戶自由定義的修飾符(Modifier),能夠用來修飾各類須要被修飾的目標」——如此晦澀的言辭,怎麼可能讓新手一會兒明白呢?(不過,等你看完這篇文章、成爲「老手」以後,你會發現這句話說得仍是挺有道理的。)何況,修飾符(好比privatepublicstaticrefout等等)都是C#語言自己的關鍵字,而Attribute看起來又與語言自己不着邊際。GodAttribute究竟是個什麼東東呢?
其實特別簡單——Attribute就是一種「附着物」——就像牡蠣吸附在船底或礁石上同樣。這些附着物的做用是爲它們的附着體追加上一些額外的信息(這些信息就保存在附着物的體內)——好比「這個類是我寫的」或者「這個函數之前出過問題」等等。
         你可能會問:這跟註釋有什麼區別呢?
         固然有區別啦!註釋是對程序源代碼的一種說明,主要目的是給人看的,在程序被編譯的時候會被編譯器所丟棄,所以,它絲絕不會影響到程序的執行。而Attribute是程序代碼的一部分,不但不會被編譯器丟棄,並且還會被編譯器編譯進程序集(Assembly)的元數據(Metadata)裏,在程序運行的時候,你隨時能夠從元數據裏提取出這些附加信息來決策程序的運行。
         口說無憑,舉個例子你立刻就會明白了——讓咱們來考慮這樣一種狀況:
         有一個類,由兩個程序員——小張和小李——共同維護。這個類是在項目中起一個「工具包」(Utilities)的做用(就像.NET Framework中的Math類同樣),裏面含了幾十個靜態方法(也就是用static修飾過的函數啦)。這些靜態方法中,一半是小張寫的、一半是小李寫的;在項目的測試中,還有一些靜態方法曾經出過bug,固然後來又被修正過了。這樣,咱們就能夠把這些方面劃分紅這樣幾類:
 
         咱們分類的目的主要是在測試的時候能夠按不一樣的類別進行測試、獲取不一樣的效果——好比統計兩我的的工做量或者對曾經出過bug的方法進行迴歸測試。
若是不使用Attribute,爲了區分這四類靜態方法,咱們有兩種方法:
1.         把這些信息體如今方法的名稱中,看起來就像這樣——
                   //...
                   public static void Li_Buged_Method_1(double arg1, double arg2) { /*...*/}
                   public static void Li_NoBug_Method_2(double arg1, double arg2) { /*...*/}
                   public static void Zhang_Buged_Method_3(double arg1, double arg2) { /*...*/}
                   public static void Zhang_NoBug_Method_4(double arg1, double arg2) { /*...*/}
         //...
                   很顯然,這樣是行不通的,由於這樣會在方法命名中遺留不少與程序邏輯自己無關的「垃圾信息」。舉個極端點兒的例子:若是小張和小李調走了,由小趙和小孫接手他們的工做,後來小趙和小孫也調走了,由小劉和小王接手維護工做……舊方法的名字不敢改,新方法的名字要用新姓氏命名,時間一長,這個類就跟《百家姓》沒什麼區別了:p
2.         另外一種方法是爲每一個方法加註釋,看起來會是這樣——
                   //...
                   public static void Method_1(double arg1, double arg2) { /*...*/}          // Created By Li, Buged
                   public static void Method_2(double arg1, double arg2) { /*...*/}         // Created By Li, NoBug
                   public static void Method_3(double arg1, double arg2) { /*...*/}          // Created By Zhang, Buged
                   public static void Method_4(double arg1, double arg2) { /*...*/}          // Created By Zhang, NoBug
         //...
                   這樣作的好處是清除了代碼中的「垃圾信息」,但狀況並無好到哪兒去。爲了統計程序員的工做量,你還得一邊看註釋一邊計數,爲了把出過bug和沒出過bug的方法分開跑,你要在執行的時候不停地把這個方法註釋掉(在調用前加//,取消它的執行)、爲那個方法取消註釋……若是是幾十個方法還好辦,若是是幾千個呢?(別不相信,我在MSN測試組裏呆着的時候,一組方法就有一千四百多個呢!)之因此出現這個問題,根本緣由是註釋會被編譯器拋棄,所以在執行期註釋絲毫幫不上咱們的忙。
         難道咱們沒有別的辦法了嗎?峯迴路轉,Attribute登場!

Attribute範例

請編譯運行下面這個程序:
 
//==== 水之真諦 ====//
//
上善若水 , 潤物無聲 //
/* [url]http://blog.csdn.net/FantasiaX[/url]  */

//#define NOBUG
#define BUGED  // C# 的宏定義必須出如今全部代碼以前。當前咱們只讓 BUGED 宏有效。
//#define LI
//#define ZHANG

using System;
using System.Diagnostics; //
注意:這是爲了使用包含在此名稱空間中的 ConditionalAttribute 特性

namespace AttributeSample
{
         class ToolKit
         {
                   [ConditionalAttribute("LI")]                                           // Attribute
名稱的長記法
                   [ConditionalAttribute("BUGED")]
                   public static void Method1() { Console.WriteLine("Created By Li, Buged."); }

                   [ConditionalAttribute("LI")]
                   [ConditionalAttribute("NOBUG")]
                   public static void Method2() { Console.WriteLine("Created By Li, NoBug."); }

                   [Conditional("ZHANG")]                                               // Attribute
名稱的短記法
                   [Conditional("BUGED")]
                   public static void Method3() { Console.WriteLine("Created By Zhang, Buged."); }

                   [Conditional("ZHANG")]
                   [Conditional("NOBUG")]
                   public static void Method4() { Console.WriteLine("Created By Zhang, NoBug."); }
         }
         class Program
         {
                   static void Main (string[] args)
                   {
                            //
雖然方法都被調用了,但只有符合條件的纔會被執行。
                            ToolKit.Method1();
                            ToolKit.Method2();
                            ToolKit.Method3();
                            ToolKit.Method4();
                   }
         }
}


執行結果:
 

實例分析:
1.         在本例中,咱們使用了ConditionalAttribute這個Attribute,它被包含在System.Diagnostics名稱空間中。顯然,它多半時間是用來作程序調試與診斷的。
2.         ConditionalAttribute相關的是一組C#宏,它們看起來與C語言的宏別無二致,位置必需出如今全部C#代碼以前。顧名思義,ConditionalAttribute是用來判斷條件的,而這組宏就是將被ConditionalAttribute所判斷的條件。凡被ConditionalAttribute「附着」了的方法,只有知足了條件纔會執行。
3.         就像船底上能夠附着不少牡蠣同樣,一個方法上也能夠附着多個ConditionalAttribute的實例。把Attribute附着在目標上的書寫格式很簡單——用方括號把Attribute一括就好了,後面緊接着寫Attribute的附着體就好了。當多個Attribute附着在同一個目標上時,把這些Attribute的方括號一個挨一個地書寫就好了(或者是在一對方括號中書寫多個Attribute),並且沒必要在意它們的順序。
4.         在使用Attribute的時候,有「長記法」和「短記法」兩種,請君自便J
由上面的第3和第4條咱們能夠推出,如下四種Attribute的使用方式是徹底等價的:
 
                   [ConditionalAttribute("LI")]                        // 長記法
                   [ConditionalAttribute("NOBUG")]
         public static void Method2() { Console.WriteLine("Created By Li, NoBug."); }
 
                   [Conditional("LI")]                                        // 短記法
                   [Conditional("NOBUG")]
         public static void Method2() { Console.WriteLine("Created By Li, NoBug."); }
 
                   [Conditional("NOBUG")]                           // 換序
                   [Conditional("LI")]
         public static void Method2() { Console.WriteLine("Created By Li, NoBug."); }
 
                   [Conditional("NOBUG"), Conditional("LI")]                      // 單括號疊加
                   public static void Method2() { Console.WriteLine("Created By Li, NoBug."); }
 
         當咱們對 Attribute 的用途有所瞭解後,咱們就能夠向 Attribute 的本質進發了! 
 
TO BE CONTINUE
請關注:
  • 《深刻淺出Attribute》(中)——Attribute的本質
  • 《深刻淺出Attribute》(下)——Attribute V.S. Property
法律聲明: 本文章受到知識產權法保護,任何單位或我的若須要轉載此文,必需保證文章的完整性(未經做者許可的任何刪節或改動將視爲侵權行爲)。若您須要轉載,請務必註明文章出處爲 51CTO 以保障網站的權益;請務必註明文章做者爲 劉鐵猛 [url]http://liutiemeng.blog.51cto.com[/url] ),並向 [email]liutm@beyondsoft.com[/email] 發送郵件,標明文章位置及用途。轉載時請將此法律聲明一併轉載,謝謝!
相關文章
相關標籤/搜索