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

首頁 > 編程 > .NET > 正文

.NET中的特殊類型成員----微軟 .NET平臺系列文章之三(譯文/趙湘寧)

2024-07-10 12:59:55
字體:
來源:轉載
供稿:網友
 
.net中的特殊類型成員

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

譯文/趙湘寧
在前面的兩篇文章中,我們研究了類型的基礎知識。本文我們將考察類型能定義的某些特殊成員。在大力簡化處理類型及其對象實例需要的語法方面,這些類型有助于面向對象設計。

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

class atype {
static int x = 5;
}

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

class atype {
static int x;

static atype() {
x = 5;
}
}

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

class atype {
static int x = 5;

static atype() {
x = 10;
}
}

    這個構造器首先初始化x=5,然后,初始化x=10。換句話說,編譯器產生的結果類型構造器首先包含靜態字段的初始化代碼,隨后是類型構造器的代碼。

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

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

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

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

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

    用這種方式使用屬性非常普通。但以我的觀點看,上述代碼不會向列出的那樣被實現。面向對象設計和編程的立約之一便是數據抽象。它的意思就時類型字段不能用公共字段暴露出來,因為它太容易被修改,太容易讓人寫出不恰當地使用這個字段的代碼,從而破壞對象的狀態。例如,某人很容易編寫下面的代碼破壞employee對象:

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

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

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

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

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

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

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

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

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

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

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

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 芮城县| 平利县| 屯门区| 郓城县| 荥经县| 湖州市| 东兴市| 石楼县| 钟山县| 四平市| 蒙阴县| 和顺县| 通城县| 黄梅县| 仁寿县| 德令哈市| 革吉县| 延津县| 图们市| 黑龙江省| 东乡族自治县| 马边| 永安市| 凤冈县| 二连浩特市| 西乡县| 潼关县| 大洼县| 大连市| 五大连池市| 陆良县| 曲靖市| 万州区| 台江县| 泸定县| 聊城市| 八宿县| 修水县| 中西区| 鄂尔多斯市| 神木县|