提起屬性,我們都不陌生。它用起來就像訪問public資料成員一樣,但實際上是調用了內部定義的相應方法。通過使用屬性保持了較好的資料封裝,而且訪問很方便,接下來我們共同複習以下CLR允許定義的兩種屬性:無參屬性和有參屬性(索引器)。
一、 無參屬性1. 定義屬性
無參屬性就是我們最常見的屬性方式,在賦值時可以加入一定的邏輯判斷。屬性的定義其實不複雜,先看個直觀的例子:
說明:
- 屬性要定義名稱和類型,且類型不能是void。
- 屬性是不能重載的。我們不能定義名稱相同、類型不同的兩個屬性。
- 屬性一般需要定義get和set方法來操作類內部的私人支援欄位,如上面的_name, _age等。Set方法中包含隱藏參數叫做value,表示賦給屬性的值。
- 唯讀唯寫屬性:可以通過省略set來定義唯讀屬性(如Count屬性),或者省略get來定義唯寫屬性。
- CLR支援靜態、執行個體、抽象和虛屬性。例子中的Name和Age就是我們最常用的執行個體屬性,Count就是靜態唯讀屬性的例子。
調用:使用屬性時會產生相應的智能感知,就像使用公用欄位一樣:
運行結果:
2. 編譯結果
通過ILDasm.exe查看中繼資料,
我們發現多了以下幾項:
① 如果屬性包含get訪問器,則會產生“get_屬性名稱” 的方法,如get_Age;
② 如果屬性包含set訪問器,則會產生“set_屬性名稱”的方法,如set_Name;
③ 中繼資料中的屬性定義項,包含了一些標記和屬性類型,並引用了get或set訪問器方法,這樣就使屬性和訪問器之間產生了關聯。例如Count屬性定義項內容:
3. 自動實作屬性——AIP
AIP(Automatically Implemented Property)是實現屬性的一種更簡潔的方式。例如上面的Student類,可以簡化為:
調用方式和運行結果與之前一致,這裡就不贅述了。
簡潔固然好,但要注意以下幾點:
① AIP的get和set方法中不能添加斷點調試。
② AIP屬性必須是同時可讀可寫的。如果只定義get或者只定義set,則必須兩個都顯式實現,不能使用AIP。
③ 想要序列化或者還原序列化的類中,不要定義AIP。因為運行時序列化引擎將欄位名持久化到了序列化流中,而且每次編譯時間這個名字還有可能改變。
二、 有參屬性——索引器
索引器是訪問器包含參數的屬性, C#是以數組的風格來公開索引器的。
1. 定義索引器。
① 和無參屬性類似,索引器也需要定義get,set訪問器,並且在set訪問器中可以使用value關鍵字。不同的是,索引器的get訪問器需要接受參數。
② 要使用this關鍵字定義索引器。
調用:索引器使得對象可按照與數組相似的方法進行索引。
2. 編譯結果
查看ILDasm.exe。
編譯之後與無參屬性類似,只不過編譯器為訪問器採用了預設名稱Item:
① 如果索引器包含get訪問器,則會產生“ get_Item” 的方法;
② 如果索引器包含set訪問器,則會產生“set_Item”的方法;
③ 中繼資料中的屬性定義項。
3. 注意事項
① 預設產生的Item名稱是可以修改的。可以通過向索引器添加“IndexerName”的attribute來實現。例如:
② 索引器可被重載。在C#中,一個類可以定義多個索引器,只要索引器的參數集不同即可。
③ 索引器可以有多個形參,例如當訪問二維數組時。
④ 索引器只能用於執行個體,不能用於靜態。
THE END。
終於寫完了。餓死了,吃飯,回家。