本文通過例項介紹了c#自定義特性。如果不能自己定義乙個特性並使用它,我想你怎麼也不能很好的理解特性。
ad:
c#自定義特性範例介紹
如果不能自己定義乙個特性並使用它,我想你怎麼也不能很好的理解特性,我們現在就自己構建乙個特性。假設我們有這樣乙個很常見的需求:我們在建立或者更新乙個類檔案時,需要說明這個類是什麼時候、由誰建立的,在以後的更新中還要說明在什麼時候由誰更新的,可以記錄也可以不記錄更新的內容,以往你會怎麼做呢?是不是像這樣在類的上面給類新增注釋:
//更新:matthew, 2008-2-10, 修改 tostring()方法這樣的的確確是可以記錄下來,但是如果有一天我們想將這些記錄儲存到資料庫中作以備份呢?你是不是要乙個乙個地去檢視原始檔,找出這些注釋,再一條條插入資料庫中呢?//更新:jimmy, 2008-1-18
//建立:張子陽, 2008-1-15
public
class democlass
通過上面特性的定義,我們知道特性可以用於給型別新增元資料(描述資料的資料,包括資料是否被修改、何時建立、建立人,這些資料可以是乙個類、方法、屬性),這些元資料可以用於描述型別。那麼在此處,特性應該會派上用場。那麼在本例中,元資料應該是:注釋型別(「更新」或者「建立」),修改人,日期,備註資訊(可有可無)。而特性的目標型別是democlass類。
按照對於附加到democlass類上的元資料的理解,我們先建立乙個封裝了元資料的類recordattribute:
publicnote:注意建構函式的引數 date,必須為乙個常量、type型別、或者是常量陣列,所以不能直接傳遞datetime型別。class recordattribute
// 對於位置引數,通常只提供get訪問器
public
string recordtype }
public
string author }
public datetime date }
// 構建乙個屬性,在特性中也叫「命名引數」
public
string memo
set
}
}
這個類不光看上去,實際上也和普通的類沒有任何區別,顯然不能它因為名字後面跟了個attribute就搖身一變成了特性。那麼怎樣才能讓它稱為特性並應用到乙個類上面呢?進行下一步之前,我們看看.net內建的特性obsolete是如何定義的:
namespace system新增特性的格式(位置引數和命名引數)首先,我們應該發現,它繼承自attribute類,這說明我們的 recordattribute 也應該繼承自attribute類。 (乙個特性類與普通類的區別是:繼承了attribute類)public
string message
} }
其次,我們發現在這個特性的定義上,又用了三個特性去描述它。這三個特性分別是:serializable、attributeusage 和 comvisible。serializable特性我們前面已經講述過,comvisible簡單來說是「控制程式集中個別託管型別、成員或所有型別對 com 的可訪問性」(微軟給的定義)。這裡我們應該注意到:特性本身就是用來描述資料的元資料,而這三個特性又用來描述特性,所以它們可以認為是「元資料的元資料」(元元資料:meta-metadata)。
(從這裡我們可以看出,特性類本身也可以用除自身以外的其它特性來描述,所以這個特性類的特性是元元資料。)
因為我們需要使用「元元資料」去描述我們定義的特性 recordattribute,所以現在我們需要首先了解一下「元元資料」。這裡應該記得「元元資料」也是乙個特性,大多數情況下,我們只需要掌握 attributeusage就可以了,所以現在就研究一下它。我們首先看上面attributeusage是如何載入到obsoleteattribute特性上面的。
[attributeusage(6140, inherited = false)]
然後我們看一下attributeusage的定義:
namespace system可以看到,它有乙個建構函式,這個建構函式含有乙個attributetargets型別的位置引數(positional parameter) validon,還有兩個命名引數(named parameter)。注意validon屬性不是乙個命名引數,因為它不包含set訪問器,(是位置引數)。public
bool inherited
public attributetargets validon
} }
// 例項化乙個 attributeusageattribute 類
attributeusageattribute usage=new attributeusageattribute(attributetargets.class);
usage.allowmultiple = true; // 設定allowmutiple屬性
usage.inherited = false;// 設定inherited屬性
但是,特性只寫成一行**,然後緊靠其所應用的型別(目標型別),那麼怎麼辦呢?微軟的軟體工程師們就想到了這樣的辦法:不管是建構函式的引數 還是 屬性,統統寫到建構函式的圓括號中,對於建構函式的引數,必須按照構造函式引數的順序和型別;對於屬性,採用「屬性=值」這樣的格式,它們之間用逗號分隔。於是上面的**就減縮成了這樣:
[attributeusage(attributetargets.class, allowmutiple=true, inherited=false)]
可以看出,attributetargets.class是構造函式引數(位置引數),而allowmutiple 和 inherited實際上是屬性(命名引數)。命名引數是可選的。將來我們的recordattribute的使用方式於此相同。(為什麼管他們叫引數,我猜想是因為它們的使用方式看上去更像是方法的引數吧。)
假設現在我們的recordattribute已經ok了,則它的使用應該是這樣的:
c#**
[recordattribute("建立","張子陽","2008-1-15",memo="這個類僅供演示")]其中recordtype, author 和 date 是位置引數,memo是命名引數。public
class democlass
c#自定義特性:attributetargets 位標記
從attributeusage特性的名稱上就可以看出它用於描述特性的使用方式。具體來說,首先應該是其所標記的特性可以應用於哪些型別或者物件。從上面的**,我們看到attributeusage特性的建構函式接受乙個 attributetargets 型別的引數,那麼我們現在就來了解一下attributetargets。
attributetargets 是乙個位標記,它定義了特性可以應用的型別和物件。
[flags]
public enum attributetargets
}
class program
}
這段程式簡單地在螢幕上輸出乙個「this is a demo class」。我們的屬性也好像使用「//」來注釋一樣對程式沒有任何影響,實際上,我們新增的資料已經作為元資料新增到了程式集中。可以通過il dasm看到:
C 自定義特性
code1 using system using system.collections.generic using system.linq using system.text namespace mylibrary.attributeclass 對於位置引數,通常只提供get訪問器 public s...
C 自定義特性
id欄位上的dbkey就是自定義特性 使用者資訊 public class user public string name 繼承attribute,實現自定義特性dbkey namespace customerattribute public dbkey public dbkey string de...
自定義特性
1.指定attributeusage特性 特性 attribute 類本身用乙個特性 system.attributeusage特性來標記。attributeusage主要用於標識自定義特性可以應用到哪些型別的程式元素上。這些資訊由它的第一引數給出,改引數是必選的,其型別是列舉型別的attribut...