直播中
Michael L. Perry
Mallard 軟件設(shè)計(jì)師
2000 年 8 月
Microsoft 對(duì)因特網(wǎng)的新視野與當(dāng)今在線內(nèi)容的網(wǎng)絡(luò)相去甚遠(yuǎn)。Microsoft 預(yù)見未來的因特網(wǎng)是一個(gè)由不同的人用不同的語言在不同的硬件平臺(tái)上開發(fā)出的互相關(guān)聯(lián)的服務(wù),可以被運(yùn)行在不同的因特網(wǎng)操作系統(tǒng)之上。
該公司為大膽設(shè)想的這個(gè)新世界所提供的就是 .Net 平臺(tái)。實(shí)際上,.Net 并不是傳統(tǒng)意義上的平臺(tái);它并不是一種公共的硬件或軟件系統(tǒng)。.Net 實(shí)際上是一個(gè)協(xié)議集合,它允許因特網(wǎng)應(yīng)用程序利用運(yùn)行在不同機(jī)器上的不同服務(wù)。
Microsoft 新戰(zhàn)略的結(jié)果就是下一代的 Microsoft Visual Studio 將有重新設(shè)計(jì)的語言,尤其是能支持 .Net 平臺(tái)。Java 將不再此程序包中,Visual J++ 也不會(huì)再有新的版本。不要擔(dān)心,Microsoft 將推出一個(gè)新的語言 C# 來填補(bǔ)這一空白。該公司動(dòng)用了其最好的資源,包括星級(jí)語言專家 Anders Hejlsberg,來開發(fā) C#。
非他莫屬:Anders Hejlsberg,語言體系結(jié)構(gòu)設(shè)計(jì)師
考慮一下 Hejlsberg 的經(jīng)歷,就不會(huì)奇怪 Microsoft 將此重任交給他了。畢竟,C# 將不是他對(duì)軟件開發(fā)方式的首次大事改革。
作為 Borland 的首席體系結(jié)構(gòu)設(shè)計(jì)師,Hejlsberg 秘密地將 Turbo Pascal 變成一種面向?qū)ο蟮?、擁有真正可視化的環(huán)境和卓越的數(shù)據(jù)庫(kù)訪問特性的應(yīng)用程序開發(fā)語言。曾經(jīng)被吹捧為“VB 殺手”的 Delphi 依然是 Borland(現(xiàn)在為 Inprise/Borland)的拳頭產(chǎn)品。
Microsoft 用豐厚的薪水、股票認(rèn)購(gòu)權(quán)和巨額的加盟獎(jiǎng)金雇請(qǐng)了 Hejlsberg 之后,Borland 曾提出通過不正當(dāng)手段吸收新成員的控告。Borland 還曾聲稱 — 提供了很少的細(xì)節(jié)來支持指控 — Hejlsberg 正在開發(fā)“Delphi for Java”。這場(chǎng)訴訟最終以 Borland 的勝利而收?qǐng)?;但是從那時(shí)起,Microsoft 已在讓 Hejlsberg 工作了。
Hejlsberg 充實(shí)了 Microsoft 的 Java 產(chǎn)品;其中格外引人注意的是,為了跟上其他 Visual Studio 語言的現(xiàn)行版本號(hào),他人為地在一個(gè)發(fā)行版中將其版本號(hào)從 1.1 提升到 6.0。實(shí)際上,這個(gè)版本號(hào)的跳躍并未夸大 6.0 與其前一版本之間的差別。Hejlsberg 添加的功能已使該語言變成一種強(qiáng)大的 Windows 應(yīng)用程序開發(fā)平臺(tái)。添加的功能包括對(duì) Windows API 的訪問;因此,利用這些新功能的程序不再具有可移植性。
Hejlsberg 對(duì) Microsoft 的 Java 產(chǎn)品的更改促使 Sun 控告 Microsoft 違反了 Java 許可協(xié)議。Sun 聲稱,Visual J++ 語言擴(kuò)展沒有保持 Java 的平臺(tái)中立性,而是將開發(fā)人員鎖定在 Microsoft 平臺(tái)上。盡管 Microsoft 的 Visual J++ 事實(shí)上是最好的 Java 編譯器,并且該公司的虛擬器(執(zhí)行 Java 字節(jié)碼的運(yùn)行期模塊)是最快的一種虛擬機(jī),但 Sun 的訴訟已有效地阻止了 Microsoft 在 Java 舞臺(tái)中的競(jìng)爭(zhēng)。
Microsoft 的反應(yīng)是完全從 Java 中退出來,并用一種新的基礎(chǔ)因特網(wǎng)平臺(tái) — .Net — 和一種新的旗幟語言 — C# 來取代它。Anders Hejlsberg 是完成后一工作的自然選擇。
證明一種新編程語言的合理性
最近有關(guān) C# 爭(zhēng)論 的一些新聞聲稱開發(fā)人員還不會(huì)收受另一種編程語言。雖然現(xiàn)在確實(shí)已經(jīng)有幾種有用的語言可供開發(fā)人員使用,但仍有空間容納另一種語言 — 假如它填補(bǔ)了仍未滿足的需要。一種新的語言畢竟只是專業(yè)人員可用來創(chuàng)建軟件解決方案的另一種工具。讓我們分析一下 Microsoft 為 C# 制定的目標(biāo),以及其他語言到目前為止還沒有滿足這些目標(biāo)的情況。
快速應(yīng)用程序開發(fā):Microsoft 為 C# 制定的最重要的目標(biāo)之一就是支持 RAD。因特網(wǎng)應(yīng)用程序必須以因特網(wǎng)節(jié)奏開發(fā);一種新語言必須易于學(xué)習(xí)和調(diào)試,而且必須生成易于更新的代碼。雖然 Delphi 和 VB 在這些方面很出色,但 C++ 卻沒有這么成功。語言本身復(fù)雜而難以掌握,而且很少有有用的 C++ 庫(kù)提供簡(jiǎn)單的接口。此外,C++ 的手動(dòng)內(nèi)存管理和復(fù)雜的類型轉(zhuǎn)換模型使它難以調(diào)試。
此外,正如我們將在下面看到的那樣,C++ 本質(zhì)上不防止由于版本不兼容而導(dǎo)致的潛在問題。盡管 Microsoft 和 Borland 對(duì)這種語言作了巨大的努力,但 C++ 仍然不適合快速應(yīng)用程序開發(fā)。
跨平臺(tái)部署:根據(jù)定義,因特網(wǎng)語言應(yīng)該支持跨平臺(tái)的部署。因?yàn)橐蛱鼐W(wǎng)是不同系統(tǒng)的一個(gè)網(wǎng)絡(luò),所以必須將服務(wù)部署到各式各樣的硬件和軟件上。 此外,客戶端軟件應(yīng)該能夠運(yùn)行在多種類型的設(shè)備上,包括 PDA 和蜂窩式便攜無線電話。 這種靈活性事實(shí)上是對(duì)除 Java 之外的所有語言的一種挑戰(zhàn)。VB 尤其只能生成在基于 Intel 微處理器的機(jī)器上運(yùn)行的 Windows 應(yīng)用程序。Delphi 也受到同樣的限制。Delphi for Linux 不久就會(huì)發(fā)布,但它也不支持因特網(wǎng)設(shè)備。VB 和 Delphi 都不符合跨平臺(tái)部署的目標(biāo)。
訪問平臺(tái)固有的資源:據(jù) Microsoft 稱,開發(fā)人員需要訪問平臺(tái)固有的資源。對(duì)于編寫強(qiáng)大的目標(biāo)應(yīng)用程序而言,這種訪問有時(shí)是必不可少的。Visual J++ 6.0 允許開發(fā)人員訪問 Windows API,Java 通常不允許這種訪問。Java 通過定義每種虛擬機(jī)實(shí)現(xiàn)的最小公分母標(biāo)準(zhǔn)來提供跨平臺(tái)的部署。Java 開發(fā)人員依據(jù)這種削弱的標(biāo)準(zhǔn)編寫代碼,而不能利用只有某些平臺(tái)才提供的更強(qiáng)大的服務(wù)。這樣,Java 無法滿足提供對(duì)平臺(tái)固有資源的訪問這一目標(biāo)。
支持 COM 和 .Net 平臺(tái):Microsoft 已將支持 COM 和 .Net 平臺(tái)確定為 C# 的最重要的目標(biāo)。當(dāng)然,目前還沒有一種語言支持 .Net 平臺(tái),因?yàn)樗栽跇?gòu)建中。與 .Net 不同,COM 已出現(xiàn)相當(dāng)一段時(shí)間了,但它仍然缺少?gòu)?qiáng)大的語言支持。大多數(shù)語言,包括 C++ 和 Delphi,都要求開發(fā)人員為他們所創(chuàng)建的每個(gè) COM 對(duì)象創(chuàng)建一個(gè)額外的 IDL 聲明、一個(gè)類工廠和專用的修飾。
某些語言廠商已提供了一些向?qū)碜詣?dòng)完成許多常見的 COM 和 OLE 任務(wù),但這些工具沒有完全隱藏 COM 的復(fù)雜性。VB 確實(shí)成功隱藏了 COM 的復(fù)雜性,但這是以犧牲功能為代價(jià)換來的。VB 不僅缺乏面向?qū)ο笳Z言的力量;它也無法支持 COM 的低級(jí)功能 — 例如,多個(gè)接口、聚集和自定義編排。簡(jiǎn)而言之,沒有一種現(xiàn)有的語言像 C# 那樣全面支持 COM。
雖然這四個(gè)目標(biāo)對(duì)于一種新語言是相當(dāng)高的,但 Hejlsberg 在工作中已拿出自己最好的經(jīng)驗(yàn)來確保 C# 實(shí)現(xiàn)這些目標(biāo)。結(jié)果是產(chǎn)生了一種語言,這種語言從 Java 和 Delphi 中借鑒東西與從 C 和 C++ 借鑒的東西一樣多(如果沒有超過的話)。請(qǐng)注意,下面的信息基于 C# 操作規(guī)程,可能不準(zhǔn)確代表最終的產(chǎn)品發(fā)行版。
C# 是一種 RAD 環(huán)境
C# 提供 Java 風(fēng)格的垃圾收集:C# 提供的最重要的 RAD 功能之一就是 Java 風(fēng)格的垃圾收集。在運(yùn)行時(shí)的任意時(shí)間內(nèi),所有沒有引用的對(duì)象會(huì)自動(dòng)刪除。通過將開發(fā)人員從手動(dòng)內(nèi)存管理任務(wù)中解放出來,垃圾收集使程序開發(fā)變得容易且不易出錯(cuò)。但是,自動(dòng)垃圾收集是耗時(shí)的,并且是不可預(yù)知的。因此,C# 允許開發(fā)人員在要求實(shí)時(shí)性能的情況下局部禁用垃圾收集 — 通過將代碼標(biāo)記為 unsafe。
C# 實(shí)現(xiàn)了 Java 和 Delphi 風(fēng)格的值/引用類型系統(tǒng):為了進(jìn)一步支持 RAD,C# 始終以 Java 和 Delphi 風(fēng)格的值/引用類型系統(tǒng)處理 C/C++ 指針模型。在這個(gè)系統(tǒng)中,內(nèi)建類型(integer、real、string,等等)、枚舉 (enumeration) 和結(jié)構(gòu) (structure) 都是值類型。賦值運(yùn)算符和比較運(yùn)算符復(fù)制并檢查這些類型的變量的值。接口、類和授權(quán)(將在后面說明)都是引用類型。賦值運(yùn)算符和比較運(yùn)算符復(fù)制并檢查這些類型的變量所引用的對(duì)象的同一性。
這種值/引用類型系統(tǒng)比 C++ 的指針模型要簡(jiǎn)單得多。它使對(duì)象處理更加容易,并消除了困擾 C 和 C++ 程序的許多內(nèi)存錯(cuò)誤。
C# 接口是獨(dú)立于類來聲明的:C# 也支持類似 Java 和 Delphi 的接口模型,接口是獨(dú)立于類來聲明的。這與 C++ 模型是對(duì)立的,在 C++ 中接口實(shí)際上就是抽象基類。接口和類都可以繼承多個(gè)接口。而類可以繼承一個(gè)基類,接口根本不能繼承類。這種模型避免了 C++ 的多繼承問題,C++ 中不同基類中的實(shí)現(xiàn)可能出現(xiàn)沖突。因此也不再需要諸如虛擬繼承和顯式作用域這類復(fù)雜機(jī)制。C# 的簡(jiǎn)化接口模型有助于加快應(yīng)用程序的開發(fā)。
類方法的聲明和定義被組合在一起:C# 簡(jiǎn)化開發(fā)的另一個(gè)方面是將類方法的聲明和定義組合在一起,與 Java 的做法十分類似。 C++ 開發(fā)人員必須為聲明(頭文件)和定義(實(shí)現(xiàn)文件)維護(hù)單獨(dú)的文件,結(jié)果使得軟件開發(fā)過程變得復(fù)雜。C# 甚至能夠自動(dòng)找出源代碼模塊之間的關(guān)系,從而使開發(fā)人員從一項(xiàng)附加的雜務(wù)中解脫出來。盡管 C++ 需要使用 #include(Delphi 需要使用 uses)來定位相關(guān)的源文件,但 C# 不需要任何額外的語句。
C# 使用方法引用,稱為授權(quán),而不使用方法指針:C# 使用方法引用來快速連接對(duì)象和方法。稱為授權(quán)的這些方法引用類似于 Delphi 的過程類型。Hejlsberg 也將同一機(jī)制引入 Visual J++ 6.0 中,不過它并不是標(biāo)準(zhǔn) Java 規(guī)范的一部分。方法引用有點(diǎn)像 C++ 的方法指針,但它要優(yōu)越、安全和有用得多。
授權(quán)是一種引用類型,它持有方法的簽名。 應(yīng)用程序可將符合這一簽名的任何方法賦給授權(quán)變量。當(dāng)調(diào)用這種授權(quán)變量時(shí),相關(guān)的方法就會(huì)被調(diào)用。與 Delphi 的過程類型不同,C# 授權(quán)自動(dòng)支持多點(diǎn)傳送。應(yīng)用程序可以將許多方法賦給一個(gè)授權(quán)變量;當(dāng)調(diào)用此變量時(shí),所有方法都會(huì)被調(diào)用。
C# 使用 Java 的簡(jiǎn)單線程同步機(jī)制。要在 C# 中實(shí)現(xiàn)線程同步,開發(fā)人員只須對(duì)關(guān)鍵的代碼塊作標(biāo)志即可。 Java 開發(fā)人員使用 synchronized 關(guān)鍵字,而 C# 開發(fā)人員使用 lock。隱藏的互斥塊將帶有標(biāo)志的代碼塊包裝起來,在任一時(shí)刻只允許一個(gè)線程執(zhí)行這段代碼。除了關(guān)鍵字不同之外,這一機(jī)制在 C# 和 Java 中是完全相同的。因?yàn)榫€程所有編程任務(wù)最容易出錯(cuò)的一種,對(duì)同步進(jìn)行簡(jiǎn)化的任何特性都有助于快速應(yīng)用程序開發(fā)。
顯式的重載聲明:最后,C# 使用顯式的重載聲明來支持 RAD。顯式的重載聲明通過保護(hù)類的方法名稱空間并指出意外的命名沖突來支持快速應(yīng)用程序開發(fā)。
C# 導(dǎo)出類的開發(fā)人員必須顯式地用關(guān)鍵字 override 標(biāo)記方法重載,正像在 Delphi 中所做的那樣。如果導(dǎo)出類包含一個(gè)與基類中的一個(gè)虛方法同名的未標(biāo)記方法,則編譯器無法明確辨別作者的意圖。
另一方面,命名沖突可能是不可避免的;尤其是當(dāng)基類和導(dǎo)出類由不同的程序員(可能為不同的公司工作)實(shí)現(xiàn)時(shí)更是不可避免。在這種情況下,編譯器將發(fā)出一個(gè)警告,并將導(dǎo)出類的方法視為一個(gè)新聲明,而不將其視為重載。
另一方面,如果程序員有意讓導(dǎo)出類中的一個(gè)新方法與基類中的某個(gè)虛方法同名,則他(或她)可以使用 new 關(guān)鍵字來阻止編譯器發(fā)出警告。
C# 的其他特性
考慮一下剛剛討論過的的所有語言特性,對(duì) RAD 的強(qiáng)大支持似乎是 Microsoft 為 C# 制定的一個(gè)最主要的目標(biāo)。但是,C# 還必須致力于其他重要的開發(fā)需求。這些需求包括跨平臺(tái)部署、訪問平臺(tái)固有的資源和對(duì) COM 和 .Net 平臺(tái)的支持。讓我們分析一下旨在支持這些需求的 C# 語言特性。
跨平臺(tái)部署:C# 以 Java 解決這一問題的相同方式解決了跨平臺(tái)部署的問題。C# 編譯器生成由 .Net 運(yùn)行時(shí)解釋的字節(jié)碼流。運(yùn)行時(shí)組件的工作方式與 Java 虛擬機(jī)十分類似;應(yīng)用程序可以部署到已安裝了 .Net 運(yùn)行時(shí)的任何設(shè)備上。
應(yīng)用程序?qū)ζ脚_(tái)固有資源的訪問:與 Java 虛擬機(jī)不同,.Net 運(yùn)行時(shí)允許程序訪問平臺(tái)固有的資源。 例如,一個(gè) C# 程序可以利用 Windows API 作為 Windows 2000 上全功能的應(yīng)用程序運(yùn)行。通過使用 Windows CE API 子集,同一個(gè)程序也可以在 PDA 上運(yùn)行。 當(dāng)然,并不是應(yīng)用程序預(yù)期的所有服務(wù)都可在所有設(shè)備上獲得。因此在所有目標(biāo)平臺(tái)上測(cè)試軟件是開發(fā)人員的責(zé)任,如有必要,開發(fā)人員還可以編寫特殊情況的代碼,那將使系統(tǒng)在缺少所需的服務(wù)時(shí)仍能夠工作。
支持 COM 和 .Net:為了支持 COM 和 .Net 平臺(tái),C# 包含一種稱為屬性的獨(dú)特語言特性。一個(gè)屬性實(shí)際上就是一個(gè) C# 類,它通過修飾源代碼來提供元信息。屬性使 C# 能夠支持特定的技術(shù),如 COM 和 .Net,而不會(huì)干擾語言規(guī)范本身。
例如,C# 提供將 C# 接口轉(zhuǎn)換為 COM 接口的屬性類。另一些屬性類將 C# 類轉(zhuǎn)換為 COM 類。執(zhí)行這些轉(zhuǎn)換不需要任何 IDL 或類工廠。某些語言觀察家聲稱所有 C# 類都是 COM 對(duì)象。這不正確 — 但通過合適的屬性,任何 C# 類很容易轉(zhuǎn)換為一個(gè) COM 對(duì)象。
隨編譯器提供的另一個(gè)屬性庫(kù)將 C# 類和函數(shù)包裝為 Web 服務(wù)。Web 服務(wù)是可在因特網(wǎng)上通過交互協(xié)議(如 SOAP)調(diào)用的托管軟件模塊。SOAP 將方法調(diào)用與它們的參數(shù)和返回值一起包裝在 XML 數(shù)據(jù)包中。Web 服務(wù)可用許多語言編寫,并可部署到許多硬件和軟件平臺(tái)上。而且,不同類型的 Web 服務(wù)可以協(xié)作組成整個(gè) Web 應(yīng)用程序。通過使用正確的屬性,程序員很容易將任何 C# 類或函數(shù)轉(zhuǎn)換為 Web 服務(wù)。
C# 不具備的特性
與 Anders Hejlsberg 的經(jīng)歷一致,C# 用來支持因特網(wǎng)應(yīng)用程序的許多特性是從 Delphi 和 Java 挑選而來的。而 Microsoft 聲稱 C# 是從 C 和 C++ 轉(zhuǎn)變而來的。因此讓我們分析一下 C# 不具備的某些 C++ 特性。
作用域和非關(guān)聯(lián)化操作符:C# 不使用 C++ 作用域操作符 (::);而是依賴于 Delphi 和 Java 中類似的點(diǎn)操作符 (.)。此外,因?yàn)樗谇懊嬲f明的 Java 和 Delphi 風(fēng)格的值/引用類型系統(tǒng),在大多數(shù)情況下 C# 不使用 C++ 的非關(guān)聯(lián)化訪問符 (->),而是再次實(shí)現(xiàn)了點(diǎn)操作符。雖然重載的點(diǎn)操作符可能使剛開始學(xué)習(xí) C# 的 C++ 程序員感到迷惑,但這對(duì) Java 和 Delphi 開發(fā)人員來說是相當(dāng)熟悉的。
引用聲明語法:因?yàn)轭?、接口和授?quán)類型默認(rèn)情況下都是引用,所以 C# 沒有 C++ 的引用聲明語法。這種新語言改為使用類似于 Delphi 聲明按引用傳遞參數(shù)的語法:
無標(biāo)記的參數(shù)是輸入?yún)?shù)
ref 關(guān)鍵字指定一個(gè)輸入/輸出參數(shù)(類似于 Delphi 的 var)
out 關(guān)鍵字指定一個(gè)輸出參數(shù)
params 關(guān)鍵字指定一個(gè)變長(zhǎng)參數(shù)列表(類似于 Delphi 的 variant open-array 參數(shù))
模板:與 Java 和 Delphi 一樣,C# 沒有模板。因此,C# 沒有支持聲明類型安全的集合的機(jī)制。每個(gè)類最終都是從共同的基類 object 導(dǎo)出的。一般集合類必須是一個(gè) object 集合,需要將它的成員不安全地下溯類型轉(zhuǎn)換為所需的類型。
盡管沒有 C++ 的這些語言特性,但 C# 仍然是一種功能強(qiáng)大的編程語言,圍繞類似 Java 和 Delphi 的特性進(jìn)行設(shè)計(jì)來支持因特網(wǎng)應(yīng)用程序。因?yàn)?C++ 對(duì)機(jī)器級(jí)的關(guān)注以及缺少 RAD 支持,所以它不適合用作因特網(wǎng)應(yīng)用程序開發(fā)語言的基礎(chǔ)。如果 C++ 開發(fā)人員需要針對(duì) .Net 平臺(tái)編寫應(yīng)用程序和服務(wù),則在 C# 發(fā)布以后將會(huì)被極力建議學(xué)習(xí)這種語言 — 請(qǐng)記住,它與 C++ 的實(shí)際區(qū)別比它們的名稱所表明的區(qū)別要大得多。
在這個(gè)過渡時(shí)期,最好學(xué)習(xí) Java 或 Delphi。不僅因?yàn)檫@兩種語言將使您更好地理解 C#,而且因?yàn)檫@兩種語言本身也是非常有用的語言。作為軟件專業(yè)人員,我們應(yīng)該利用可獲得的最好的工具。
作者簡(jiǎn)介
Michael L. Perry 六年多來一直從事專業(yè) Windows 開發(fā),并擁有 COM+、Java、XML 等方面的專家經(jīng)驗(yàn)以及目前塑造編程前景的其他技術(shù)。他于 1998 年成立了 Mallard Software Designs 公司,在公司內(nèi)他用數(shù)學(xué)嚴(yán)格證明軟件設(shè)計(jì) — 在實(shí)現(xiàn)之前首先建立解決方案的正確性。