国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

.NET中的特殊類型成員

2024-07-10 12:59:59
字體:
供稿:網(wǎng)友
.net中的特殊類型成員

----微軟 .net平臺系列文章之三

譯文/趙湘寧

在前面的兩篇文章中,我們研究了類型的基礎(chǔ)知識。本文我們將考察類型能定義的某些特殊成員。在大力簡化處理類型及其對象實例需要的語法方面,這些類型有助于面向?qū)ο笤O(shè)計。

類型構(gòu)造器
你已經(jīng)熟悉了什么是構(gòu)造器,它負(fù)責(zé)對象實例狀態(tài)的初始化。除了實例構(gòu)造器以外,microsoft(r).net公共語言運行時(clr)還支持類型構(gòu)造器(也叫做靜態(tài)構(gòu)造器、類構(gòu)造器或類型初始化)。類型構(gòu)造器可被應(yīng)用到接口,類和數(shù)值類型。它允許任何在類型中聲明的成員被訪問之前實現(xiàn)必要的初始化。類型構(gòu)造器不需要參數(shù)并且總是返回void類型。類型構(gòu)造器只訪問類型的靜態(tài)字段并且其通常的目的是初始化這些字段。在類型的任何實例被創(chuàng)建之前以及類型的任何靜態(tài)字段或方法被引用之前,必須要保證已經(jīng)運行了類型構(gòu)造器。
許多語言(包括c#)在定義類型時都自動產(chǎn)生類型構(gòu)造器。但是某些語言需要顯式(手工)實現(xiàn)類型構(gòu)造器。
為了理解類型構(gòu)造器,讓我們研究一下列在c#中定義的類型:

class atype {
static int x = 5;
}

在建立這個代碼時,編譯器自動地為產(chǎn)生atype類型構(gòu)造器。這個構(gòu)造器負(fù)責(zé)初始化靜態(tài)字段x為值5。如果你使用ildasm,很容易認(rèn)出類型構(gòu)造器方法,因為它們的名字都是.cctor(對于類構(gòu)造器而言)。
在c#中,通過在類型中定義靜態(tài)構(gòu)造器方法,你可以自己實現(xiàn)類型構(gòu)造器。關(guān)鍵字static的使用意味著這時類型構(gòu)造器,而不是實例構(gòu)造器。下面是一個非常簡單的例子:

class atype {
static int x;

static atype() {
x = 5;
}
}

這個類型定義與前面的相同。注意類型構(gòu)造器決不能試圖創(chuàng)建自己的類型實例,而且構(gòu)造器也不能引用類型的非靜態(tài)成員。
最后,如果你用c#編譯器編譯下列代碼,它產(chǎn)生單獨的類型構(gòu)造器方法:

class atype {
static int x = 5;

static atype() {
x = 10;
}
}

這個構(gòu)造器首先初始化x=5,然后,初始化x=10。換句話說,編譯器產(chǎn)生的結(jié)果類型構(gòu)造器首先包含靜態(tài)字段的初始化代碼,隨后是類型構(gòu)造器的代碼。

屬性
許多類型定義的屬性可以被重新獲得或修改。這些屬性常常都是用類型字段成員來實現(xiàn)的。例如,下面是包含有兩個字段的類型定義:

class employee {
public string name;
public int32 age;
}

如果創(chuàng)建這個類型的實例,那么很容易用以下代碼得到或設(shè)置屬性:

employee e = new employee();
e.name = "jeffrey richter"; // 設(shè)置名字屬性
e.age = 36; // 設(shè)置年齡屬性

console.writeline(e.name); // 顯示 "jeffrey richter"

用這種方式使用屬性非常普通。但以我的觀點看,上述代碼不會向列出的那樣被實現(xiàn)。面向?qū)ο笤O(shè)計和編程的立約之一便是數(shù)據(jù)抽象。它的意思就時類型字段不能用公共字段暴露出來,因為它太容易被修改,太容易讓人寫出不恰當(dāng)?shù)厥褂眠@個字段的代碼,從而破壞對象的狀態(tài)。例如,某人很容易編寫下面的代碼破壞employee對象:

e.age = -5; //人的年齡怎么會是-5呢?

所以說,在設(shè)計類型時,我強(qiáng)烈建議所有字段都是私有的(private)或至少是受保護(hù)的(protected)——決不要公共的(public)。然后,讓使用類型的人能get或set屬性,專門為此提供方法。打包對字段的訪問的方法就叫做存取器(或訪問器方法)方法。這些方法能隨時實現(xiàn)完整性檢查并保證對象的狀態(tài)不被破壞。例如,我重寫了前面定義過的employee類,代碼如圖一。雖然這是一個簡單的例子,但你能從中明白抽象數(shù)據(jù)字段的巨大好處,你還能從中明白如何輕松實現(xiàn)只讀屬性,或者僅僅通過不去實現(xiàn)某個存取器方法來輕松達(dá)到只寫屬性。
圖一中顯示的數(shù)據(jù)抽象方法有兩個缺點。第一,因為要實現(xiàn)附加的函數(shù),所以要多寫一些代碼。第二,類型的使用者現(xiàn)在必須要調(diào)用方法而不是僅僅引用單個的字段名:

e.setage(36); // updates the age
e.setage(-5); // throws an exception

我想,所有的人都會同意這些缺點與其優(yōu)點比起來顯得微不足道,但運行時仍然提供了一種屬性機(jī)制,多少使得第一個缺點容易忍受了,并且完全消除了第二個缺點。
圖二中的類使用了屬性,其功能和圖一所示的類相同。正如你所看到的,屬性簡化了一些代碼,但更重要的是允許調(diào)用這項下面一樣寫自己的代碼:

.age = 36; // 更新年齡
e.age = -5; // 擲出異常throws an exception

get屬性存取器的返回值和傳遞到set屬性存取器參數(shù)值類型相同。set屬性存取器的返回值是void,而get屬性存取器沒有入口參數(shù)。屬性可以是靜態(tài)的、虛擬的、抽象的、內(nèi)部的、私有的、保護(hù)的或公共的。另外,屬性可以在接口中定義,關(guān)于這一點將在后面討論。
我還應(yīng)該指出屬性不必于字段關(guān)聯(lián)。例如,類型system.io.filestream定義了一個長度屬性,它返回流中的字節(jié)數(shù)。當(dāng)長度屬性的get方法被調(diào)用時,這個長度不是由字段提供,而是調(diào)用另一個函數(shù)請求底層操作系統(tǒng)返回打開文件流的字節(jié)數(shù)。
當(dāng)你創(chuàng)建屬性時,編譯器實際上發(fā)出專門的get_proname和/或set_proname存取器方法(這里proname是屬性名)。大多數(shù)編譯器會理解這些專用方法并允許開發(fā)人員存取這些有專門屬性語法的方法。但是,遵守公共語言運行時規(guī)范的編譯器不需要完全支持屬性,只要支持專用存取方法調(diào)用即可。
另外,對于完全支持屬性的編譯器來說,在定義和使用屬性時使用的語法稍有不同,例如帶受管擴(kuò)展的c++需要使用_property關(guān)鍵字。

索引屬性
某些類型,如system.collections.sortedlist暴露邏輯元素列表。為了能輕松存取這種類型中的元素,可以定義一個索引屬性(也叫索引器-indexer)。圖三顯示的是一個索引屬性的例子,其索引器的的使用極其簡單:

bitarray ba = new bitarray(14);
for (int x = 0; x < 14; x++) {
// 置所有偶數(shù)位為“on”
ba[x] = (x % 2 == 0);
console.writeline("bit " + x + " is " + (ba[x] ? "on" : "off"));
}

圖三的bitarray例子中,索引器帶一個int32參數(shù):bitposition。索引器必須至少帶一個參數(shù),參數(shù)個數(shù)可以是兩個或更多。這些參數(shù)(以及返回類型)可以是任何類型。創(chuàng)建以string作為參數(shù)的索引器查找聯(lián)合數(shù)組中的值是十分普通的事情。一種類型可以提供多個索引器,只要其原型不同。
就像set屬性,set索引器存取方法包含一個隱藏的參數(shù),值,當(dāng)存取方法被調(diào)用時,它表示想得到一個新的值。bitarray的set存取方法顯示了這個參數(shù)值的使用。

一個設(shè)計良好的索引器應(yīng)該具備get和set兩個存取方法。即便你能只實現(xiàn)get存取方法(對于只讀語義)或者只實現(xiàn)set存取方法(對于只寫語義),建議你的索引器實現(xiàn)兩個存取器。理由很簡單,索引的使用者不希望只有半個行為。例如,當(dāng)編寫下面兩行代碼時,使用者不想看到編譯器出錯:
string s = someobj[5]; // 如果有存取器,編譯 ok
someobj[5] = s; //如果沒有存取器,編譯出錯

索引器總是起類型實例的作用,并且不能被聲明為靜態(tài)。但它可以是公共的、私有的、保護(hù)的或內(nèi)部的。
當(dāng)你創(chuàng)建索引屬性時,編譯器實際上會發(fā)布專門的get_item和/或set_item存取器方法。大多數(shù)編譯器都會理解這些專門的方法并且會允許開發(fā)人員利用專門的索引屬性語法存取這些方法。但是,與cls(公共語言系統(tǒng))兼容的編譯器不需要完全支持索引屬性;只要編譯器支持專用存取器調(diào)用即可。
同樣,對于完全支持索引屬性的編譯器在定義和使用這些屬性的時候,需要的語法稍有差別。例如,c++受管擴(kuò)展需要使用_property關(guān)鍵字。

結(jié)論
本文中所討論的概念對于所有.net的程序員來說極其重要。我所提到的特殊的類型成員使組件成為公共語言運行時最重要的內(nèi)容。也就是說,現(xiàn)代組件被設(shè)計成支持屬性。
下一篇文章我將介紹委派和事件成員,因為它們與基于組件的應(yīng)用開發(fā)和設(shè)計是不可分割的一個整體。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 西乌| 孙吴县| 霍山县| 镇原县| 万载县| 潼关县| 罗甸县| 深泽县| 白玉县| 甘洛县| 蒙自县| 太仆寺旗| 德安县| 江安县| 永修县| 海淀区| 鹤庆县| 长岭县| 苗栗县| 广元市| 乐至县| 汝州市| 桃园市| 房产| 方城县| 景泰县| 海门市| 武冈市| 勐海县| 永丰县| 濮阳市| 张家界市| 绥江县| 仲巴县| 始兴县| 忻州市| 沙雅县| 张家川| 乐平市| 揭阳市| 新乡县|