Custom Attributes 客製化特徵

客製化特徵 Custom Attributes

 

所謂的客製化特徵 (Custom Attributes) ,是C#中一個可以讓你去自定義你的類別中屬性或是方法的一個特製的屬性,是針對屬性、方法甚至是類別的本身再去外掛的一個屬性,這個屬性你平常建構起來之後,是看不到它,但是它就確實存在你實體化後的物件中,你必須要透過一些特殊的方法去把它取出來。

這感覺有點像是我在進入到捷運站的時候,在捷運站我會拿著一張悠遊卡進站,進站的時候我只需要將悠遊卡拿出來,往卡機一刷就可以自動進行扣款,那個悠遊卡其實就是一張 RFID 高頻的 Mifare 卡,在你手上拿的這張卡片你可以看到它是印有一些圖騰,另外會有一個卡號,還有一些說明...等資訊,你可以理解的是這上面寫的那些資訊就是它的一些相關的屬性,例如有名稱、備註、卡號...等。

圖1. 悠遊卡示意圖

但是其實在這張悠遊卡中它是有一些隱藏資訊的,例如說他會存放是否為老人卡、學生卡或是一般成人卡,以及卡裡面的金額,進站點...等等這些資訊 (會友另外一張專門來說明 Mifare 卡),但是這些資訊你看不到,而這些被隱藏起來的資訊就好像我們的Custom Attributes。

因此我們可以針對 Method、Property 都可以去定義 Custom Attributes,要定義 Custom Attributes 首先你必須要先建立一個 Class 來繼承 System.Attribute 這個父類別,一旦你繼承了 System.Attribute 這個父類別之後,你的這個類別就可以當作是 Custom Attributes 來使用,如圖2. 自定義 Custom Attributes 類別

圖2. 自定義 Custom Attributes 類別

再圖2中我們定義了一個 EAPQueueAttributes 的類別,在這個類別中,我定義了三個自定義屬性,分別是「Index」、「Name」與「IsList」這三個屬性,基本上定義到這裡就已經將我們的客製化特徵定義完畢了,接下來就可以去使用者個 Custom Attributes。

如何使用,其實很簡單,就是在你要自定義的那個類別中 Using 到那個類別的 Namespace,再將你要自定義特徵的屬性上方,定義出你的 Custom Attributes 的名稱,接下來你就可以去設定你的特徵資料值,如圖3. 設定 Custom Attributes 相關資料

圖3. 設定 Custom Attributes 相關資料

使用方式很簡單,如圖3 一樣在你的屬性或是方法上加上一個中跨號 (VB.NET 是 <> 角跨號),並且在中跨號裡面去定義 Custom Attributes 的名稱,接下來就可以在Custom Attributes 名稱的後方直接指定你的特徵內容,定義完畢之後你對他賦予的相關資訊就完成了。

接下來就是我要如何在系統運行的時候,將這些 Custom Attributes 的隱藏資料讀取出來加以運作呢?我們要讀取這些 Custom Attributes 的資料時,同樣的也是要透過 Reflection 的機制來獲取,因此我們在抓取這些資料之前,我們也是一樣要先將我要抓取的物件轉換成 Type 型別,來獲取該類別的資訊,因此可以透過 GetType() 的方法,來抓取到物件對應的類別資訊,如

var ClassInfo = BarCodeInfo.GetType();

在早前文章(透過 Reflection 建構通用型 SOAP 入口) 中有介紹到我們透過 GetType() 的方法,可以抓取到該物件的類別資訊,因此我有了類別資訊後,可以再透過 GetProperty() 的方法來獲取到該類別的所有屬性資訊,如

var PropertyInfo = BarCodeInfo.GetType().GetProperty([PropertyName]);

或是透過 GetProperties() 來獲取到所有該類別的公開屬性資訊,如

var PropertyInfo = BarCodeInfo.GetType().GetProperties();

另外也可以透過早前文章介紹到的 GetMethod() 或是 GetMethods() 來獲取該類別的所有公開方法,如下範例。

var MethodInfo = BarCodeInfo.GetType().GetMethod([MethodName]);
var MethodInfo = BarCodeInfo.GetType().GetMethods();

當然如果要獲取該類別中所有全域變數的宣告也是有 GetField() 以及 GetFields() 的方法來獲取到該類別的全域變數資訊,如下範例

var FieldInfo = BarCodeInfo.GetType().GetField([FieldName]);
var FieldInfo = BarCodeInfo.GetType().GetFidles();

而我們如果要獲取 Custom Attributes 資訊時,必須要明確知道你要獲取的 Custom Attributes 是附加在哪個地方上,所以如果你要抓取類別上的 Custom Attributes 就必須要先透過 GetType() 的方法來獲取到類別的資訊;如果你要抓取的是方法上的 Custom Attributes 就要先透過 GetMethod() 的方法來取得到指定類別資訊;依此類推,如果我依據圖3 中所定義的,該類別的 Custom Attributes 都是設定在屬性上,因此我們就必須要先透過 GetProperty() 或是 GetProperties() 的方法,來獲取到類別上屬性的資訊,當獲取到屬性資訊後,可以再透過 GetCustomAttributes() 的方法來獲取到該屬性上所定義的所有客製化特徵資訊,如下範例

var AttrInfo = BarCodeInfo.GetType().GetProperty("[PropertyName]").GetCustomAttributes(false);

請注意,這裡是獲取到該屬性、方法、類別或變數的所有 Custom Attributes 資訊,一個方法上面可以擁有多個 Custom Attributes 如圖4. 定義多個 Custom Attributes 資訊

圖4. 定義多個 Custom Attributes 資訊

在圖4 中可以看到這個 Class 中被定義了三個 Custom Attributes 資訊,所以當你透過 GetCustomAttributes() 的方法來獲取 Custom Attributes 時,你會就會獲取到一個 object[] 這個物件陣列中會有三個元素,分別就是圖4中所定義的那三個 Attributes 的物件資訊;請注意,你這時候獲取到的是物件,也就是它是一個已經配置過記憶體的物件,裡面已經有包含了你當初所設定在那些 Custom Attributes 中的資料,獲取到之後便可以直接拿來使用或判斷,如圖5. 獲取 Custom Attributes 範例。

圖5. 獲取 Custom Attributes 範例

在圖5 中可以看到他首先先宣告並實體化在圖3中所定義的那個 EAP_BarcodeCheck 的物件,接著它透由 GetType() 轉換成類別資訊,再透過 GetProperties() 獲取到所有屬性資訊 (因為圖3 中所有的 ColumnIndexList 是定義在屬性中)。

獲取到所有屬性資訊後,又宣告了一個 ColumnIndexList 的清單物件要來收集所有欄位被定義在Custom Attributes 中的位置,最後我用了一個 Foreach 將所有的屬性逐一取出來,並且透過 GetCustomAttributes() 來抓取到該屬性中所有的 Custom Attributes,並透過 Linq 的方式抓取到屬於EAPQueueAttributes 的 Attribute,如此我便獲取到該 Custom Attributes 中所定義的 Column Name 以及 Column Index,就可以將資料存放到早前選告的 ColumnIndexList 的清單中。

透過這樣的操作,我便可以獲取到類別中 Custom Attributes,並且可以再透過 Reflection 的機制可以在達到更多的操作,後續我會使用這樣的手法,來達到更多我要講解的東西;簡單說一個目前有做過的真實範例:當我收到一筆資料時,我會去定義這筆資料可以透由「@」去做區隔。

CheckIn@4523||1||AS4382G||1


如上範例所示@前面的 CheckIn 便是我要去本類別中在 Method 中的 Custom Attributes 的資訊裡,被定義跟 CheckIn 一樣的方法,如下範例:
 

[ATTR_MessageDefinition(Name = "CheckIn")]
private void HandleLotCheckInInfo(object pInputInfo) {
  .... .... .... ....
  .... .... .... ....
}

[ATTR_MessageDefinition(Name = "CheckOut")]
private void HandleLotCheckOutInfo(object pInputInfo) {
  .... .... .... ....
  .... .... .... ....
}

而@後面的資料,就是我調用對應的方法時,要帶入的資料,動態調用的方法,請參閱透過 Reflection 建構通用型 SOAP 入口,這裡不多做解釋。