程式員天地
Robert Hess和Jeffrey Richter(著名的編程作家、專欄作家和諮詢專家)的談話。 ROBERT HESS: 歡迎回來。我們正要涉及到有關C#編程方面的問題。為了有助於我們理解這些問題,我邀請我的好朋友Jeffery Richter到這裡來。Jeffery恰好是一名撰寫了很多編程書籍的程式員,他最新的一本書為Programming Server Side Applications for Windows 2000。現在您也是一位諮詢專家並且擁有自己的公司Wintellect,是嗎?
JEFFREY RICHTER: Wintellect。
ROBERT HESS: 我猜您有一個網站吧?
JEFFREY RICHTER:有,Wintellect.com。我們專門從事培訓、調試和廣告。
ROBERT HESS: 好了,我瞭解到您最近做了不少有關C#的工作。
JEFFREY RICHTER: 是的,至今已一年有餘了,我花了很大的精力一直專攻C#的編程。
ROBERT HESS: 這樣微軟就會對您有所協助,因為您並不是微軟的職員……
JEFFREY RICHTER: 對。
ROBERT HESS:他們只是協助您的把C#當成一種語言理解,那麼您就可以寫出更多象這樣的書?
JEFFREY RICHTER:是的,他們希望我寫更多的書,我得到了協助,發現了bug,出席了類似的一些規範會議,並與人們交流,因此我覺得學到了很多的東西,而不只是寫書,而事實在某種程度上也對C#做出了貢獻。所以我可以告訴您,當最初開始時,我感興趣的第一個東西就是這種新的語言,我將用它來寫所有的代碼,我知道這些代碼是為可以預見的未來寫的,讓我們暫且不提。我具有非常深厚的C、C++背景,在閱讀與C#相關文檔和編程參考等資料一個星期之後,我就覺得已經相當精通C#了。並且在一周之內,我能夠真正地寫出一些有用的東西。
ROBERT HESS:僅僅一周之後。
ROBERT HESS:既然您從事這項工作已經一年多了,那麼您注意到了在這段時間裡這種語言自身的演變嗎?是否它們今天仍然與一年以前的十分相同?
JEFFREY RICHTER:我認為十分相同。但肯定存在著一些小技巧(tweak),在beta測試階段確實存在著這些回應,存在著許多非確定性解構函式(non deterministic destructor)、對象的析構(destruction of objects)等類似的東西。因此,基底類別庫已經增加了一個iDisposable介面,我想它將會出現在beta 2.0版中,而不是在beta 1.0版中。同時C#已增加了一些新的語言結構,以協助你獲得與對象的確定性析構(deterministic destruction of objects)關係密切的東西。所以我要說,微軟已經十分在意人們對該語言的評價了,並且他們還企圖在其中加入新的東西以做出回應。我同樣瞭解到,將來在1.0版之後,他們計劃要增加泛型(generics),這有點類似C++中的模板,而我可以肯定,為了支援這些效能,C#就要發展。實際上當處於公用語言運行庫(common language runtime)之中時,所有的語言都能用到泛型。
ROBERT HESS:因為它們是其中的一部份,又因其是公用語言運行庫,所以它們有權使用所有的那些功能。那麼您認為,C#作為一種語言總的來說究竟怎麼樣?
ROBERT HESS:哈!談到組合語言啦?
JEFFREY RICHTER:是的,談到組合語言了。我的意思是,它使您完全有權訪問平台的底層,但在組合語言的環境中效率會很低,有這麼多的程式您必須一行一行地寫。所以,C#語言高出了一個層次。而在C#中的有些效能並不是很常用,因此象Anders 這樣的C#設計者已決定不必將其公開了。在某些情況下,為了訪問C#沒有提供的runtime功能,我可能會求助於另外一種語言。但總的來說,C#是最高層的語言,它允許我在這樣的環境中按自己的需求解決大量的問題,而且效率極高。
ROBERT HESS:並不是所有的問題,而僅僅只是大部份?
JEFFREY RICHTER:不,極少會出現這種情況:我還需要訪問某些東西,而C#卻不讓訪問。這是另外一方面,我只是認為大家非常容易忘卻的是,當您想要訪問.NET的一些功能而C#或某些語言卻不提供給您時,可以轉到別的語言。只需編碼建立這個方法,可能是一個靜態方法(static method),類中的靜態方法,用APL或COBOL或凡是您選擇的語言,或許派生,然後用某些語言實現實體方法,而這種語言可能真的讓您訪問某些底層功能。因此,我認為這是一個功能非常強大的範例,以前我從未真正地領會過要選擇最佳的語言去完成工作。
ROBERT HESS:好了,我打賭各位觀眾可能想要看一些C#代碼的例子,以便能理解我們談論到的一些問題。您有例子示範給我們看嗎?
JEFFREY RICHTER:有。我確實的帶來了一個原始碼檔案,裡面有一些例子,能勉勉強強地應付,在節目結束後,我會給您的。歡迎您把它上傳到網站上,以讓大家可以下載。所以在這裡,如果你樣喜歡的話,我首先要示範的是:在C#中,每一個方法必須位於類中。沒有全域方法,也沒有位於類之外的變數,所以每一樣東西都會被限定在一定的範圍內。
using System;
class App {
public static void Main() {
Console.WriteLine("Hello World");
}
}
這是一個必須保留的hello world程式,非常簡單。在程式裡,有一個類叫App,在這個類裡,我擁有自己的一個Main方法,並且Main是一個靜態方法,因為它必須從外面調用。我們不必擁有App的一個執行個體就可以調用Main。在我這個例子裡,Main返回void,並且沒有接受參數。簡單地在Main的內部,它調用了Console.WriteLine,在顯示器上面顯示出"Hello World"。所以這是您可以寫的、能學到相關概念的最小程式了。
ROBERT HESS:在C#中Main仍然是一個保留的方法嗎?就象在C++中?
ROBERT HESS:絕妙的技巧。您也使用象argv、 argc這樣的參數,預設地傳遞給Main函數嗎?
using System;
class App {
public static void Main(string[] args) {
Console.WriteLine("Hello World");
}
}
JEFFREY RICHTER:是,隨您的便。在這裡,我將當場修改這些代碼,也就是說,string是一個字串數組,args
按我在投影片中播放的定義。順便地,這個args是什麼呢?是一個資料類型!它是一個指向字串的指標,或者是一個指向字串的引用。說到指標,您只見過帶*號的,但args確實是一個指標。當Main被調用之前,啟動代碼早已解析命令列,並且建立一個字串數組,接著把指標傳入該數組。象對args.length類似的調用使我可以解決一些問題,該調用會返回數組的length屬性,此屬性含有數組元素的個數,然後我正好可以利用一個正常的for語句進行迴圈,或者可以用C#的for each,特殊的for each語句用於快速的迴圈。
ROBERT HESS:很新穎,這是在C或C++中所沒有的。
JEFFREY RICHTER:正確。而我確實也有示範的代碼,我找到了。
static void ArrayDemo() {
// 聲明一個指向數組的引用
Int32[] ia; // 預設值為 null
ia = new Int32[100];
ia = new Int32[] { 1, 2, 3, 4, 5 };
.
.
.
這是一個具有數組的代碼的例子,所以我會略為提一下。在這個例子裡,首先聲明一個指向Int32s數組的引用,隨意取一個"ia"用於整數數組。它只不過是一個指標,具有32位(bit)或64位值,如果它們仍在64位系統上運行,總是會被初始化為null,引用總是被初始化為null直到明確地設定它為止。下面一行,我隨意new(構造)了一個有100個Int32值的數組。new返回一個引用,接著我把這個引用存到"ia"變數中。下一行只不過示範了另外一種構造的方式,這裡我又new了一個Int32s數組,這種專門的C#句法以一個左大括弧開始,後面跟著數組的元素,當然元素之間要用逗號分開,然後是一個右括弧。當您第一次見到這種句法時,會覺得它有點笨拙。這隻不過是new的另外一種用法,當然它可以推算出元素的個數。
ROBERT HESS: 而這隻不過是預定義了值:
.
.
.
// 顯示數組的內容
foreach (Int32 x in ia)
Console.Write("{0} ", x);
//使用多維陣列
StringBuilder[,] sa = new StringBuilder[10][5];
for (int x = 0; x < 10; x++) {
for (int y = 0; y < 5; y++) {
sa[x][y] = new StringBuilder(10);
}
}
// 使用數組的數組(jagged arrays)
Int32 numPolygons = 3;
Point[][] polygons = new Point[numPolygons][];
polygons[0] = new Point[3] { ... };
polygons[1] = new Point[5] { ... };
polygons[2] = new Point[10] { ... };
}
JEFFREY RICHTER:是的,很正確。這就是foreach,它出現在代碼的第一行。"foreach"是C#句法,我肯定所有的.NET語言都會提供此句法,它是一個極其通用的編程典範,用這種方式,就可以遍曆集合裡的元素。因此,這裡的foreach Int32 x中,"x"是一個變數,Int32當然是一種類型,接著我把引用賦予了數組。foreach將會自動推算出數組中有多少個元素,並且每當迴圈到Console.Write時,就會顯示出元素的值,然後再移向下一個元素。
ROBERT HESS:而"for (i=0, i<ia.length, i++)"也做同樣的工作,但如果您想要遍曆所有的元素的話,這種方式有些笨拙以至難於遵循,所以一直持續不斷地做十分相同的事情,我想會更加容易。