明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

A Comparative Overview of C#中文版(二)

[摘要]在GameTest里,我們分別創(chuàng)建了一個(gè)game和一個(gè)監(jiān)視game的referee,然后,然后我們改變game的Score去看看referee對(duì)此有何反應(yīng)。在這個(gè)系統(tǒng)里,game沒(méi)有referee的...
在GameTest里,我們分別創(chuàng)建了一個(gè)game和一個(gè)監(jiān)視game的referee,然后,然后我們改變game的Score去看看referee對(duì)此有何反應(yīng)。在這個(gè)系統(tǒng)里,game沒(méi)有referee的任何知識(shí),任何類都可以監(jiān)聽(tīng)并對(duì)game的score變化產(chǎn)生反應(yīng)。關(guān)鍵字event隱藏了除了+=和-=之外的所有委托方法。這兩個(gè)操作符允許你添加(或移去)處理該事件的多個(gè)事件處理器。
【譯注:我們以下例說(shuō)明后面這句話的意思:
public class Game
{
public event ScoreChangeEventHandler ScoreChange;
protected void OnScoreChange()
{
if (ScoreChange != null) ScoreChange(30, ref true);//在類內(nèi),可以這么使用
}
,但在這個(gè)類外,ScoreChange就只能出現(xiàn)在運(yùn)算符+=和-=的左邊】
 你可能首先會(huì)在圖形用戶界面框架里遇到這個(gè)系統(tǒng)。game好比是用戶界面的某個(gè)控件,它根據(jù)用戶輸入觸發(fā)事件,而referee則類似于一個(gè)窗體,它負(fù)責(zé)處理該事件。
 【作者注:委托第一次被微軟Visual J++引入也是Anders Hejlsberg設(shè)計(jì)的,同時(shí)它也是造成Sun和微軟在技術(shù)和法律方面爭(zhēng)端的起因之一。James Gosling,Java的設(shè)計(jì)者,對(duì)Anders Hejlsberg曾有過(guò)一個(gè)故作謙虛聽(tīng)起來(lái)也頗為幽默的評(píng)論,說(shuō)他因?yàn)楹虳elphi藕斷絲連的感情應(yīng)該叫他“方法指針先生”。在研究Sun對(duì)委托的爭(zhēng)執(zhí)后,我覺(jué)得稱呼Gosling為“一切都是一個(gè)類先生”好像公平些J 過(guò)去的這幾年里,在編程界,“做努力模擬現(xiàn)實(shí)的抽象”已經(jīng)被很多人代之以“現(xiàn)實(shí)是面向?qū)ο蟮,所以,我們?yīng)該用面向?qū)ο蟮某橄髞?lái)模擬它”。
 Sun和微軟關(guān)于委托的爭(zhēng)論可以在這兒看到:
http://www.Javasoft.com/docs/white/delegates.html http://msdn.microsoft.com/visualj/technical/articles/delegates/truth.asp 】
6.枚舉
 枚舉使你能夠指定一組對(duì)象,例如:
聲明:
public enum Direction {North, East, West, South};
使用:
Direction wall = Direction.North;
這真是個(gè)優(yōu)雅的概念,這也是C#為什么會(huì)決定保留它們的原因,但是,為什么Java卻選擇了拋棄?在Java中,你不得不這么做:
聲明:
public class Direction
{
public final static int NORTH = 1;
public final static int EAST = 2;
public final static int WEST = 3;
public final static int SOUTH = 4;
}
使用:
 int wall = Direction.NORTH;
看起來(lái)好像Java版的更富有表達(dá)力,但事實(shí)并非如此。它不是類型安全的,你可能一不小心會(huì)把任何int型的值賦給wall而編譯器不會(huì)發(fā)出任何抱怨【譯注:你顯然不可以這么寫:Direction wall = Direction.NORTH;】。坦白地說(shuō),在我的Java編程經(jīng)歷里,我從未因?yàn)樵撎幏穷愋桶踩ㄙM(fèi)太多的時(shí)間寫一些額外的東西來(lái)捕捉錯(cuò)誤。但是,能擁有枚舉是一件快事。C#帶給你的一個(gè)驚喜是—當(dāng)你調(diào)試程序時(shí),如果你在使用枚舉變量的地方設(shè)置斷點(diǎn),調(diào)試器將自動(dòng)譯解direction并給你一個(gè)可讀的信息,而不是一個(gè)你自己不得不譯解的數(shù)值:
聲明:
public enum Direction {North=1, East=2, West=4, South=8};
使用:
Direction direction = Direction.North Direction.West;
if ((direction & Direction.North) != 0)
//....
如果你在if語(yǔ)句上設(shè)置斷點(diǎn),你將得到一個(gè)你可讀的direction而不是數(shù)值5。
【譯注:這個(gè)例子改一下,會(huì)更有助于理解:
聲明:
public enum Direction {North=1, East=2, West=4, South=8, Middle = 5/*注意此處代碼*/};
使用:
Direction direction = Direction.North Direction.West;
if ((direction & Direction.North) != 0)
//....
如果你在if語(yǔ)句上設(shè)置斷點(diǎn),你將得到一個(gè)你可讀的direction(即Middle)而不是數(shù)值5】
【作者注:枚舉被Java拋棄的原因極有可能是因?yàn)樗梢杂妙惔。正如我上面提到的,單單用類我們不能夠象用別的概念一樣更好地表達(dá)某個(gè)特性。Java的“如果它可以用類處理,那就不引入一個(gè)新的結(jié)構(gòu)”的哲學(xué)的優(yōu)點(diǎn)何在?看起來(lái)最大的優(yōu)點(diǎn)是簡(jiǎn)單—較短的學(xué)習(xí)曲線,并且無(wú)需程序員去考慮做同一件事的多種方式。實(shí)際上,Java語(yǔ)言在很多方面都以簡(jiǎn)化為目標(biāo)來(lái)改進(jìn)C++,比如不用指針,不用頭文件,以及單根對(duì)象層次等。所有這些簡(jiǎn)化的共性是它們實(shí)際上使得編程—唔—簡(jiǎn)單了,可是,沒(méi)有我們剛才提到的枚舉、屬性和事件等等,反而使你的代碼更加復(fù)雜了】
7.集合和foreach語(yǔ)句
 C#提供一個(gè)for循環(huán)的捷徑,而且它還促進(jìn)了集合類更為一致:
在Java或C++中:
1. while (! collection.isEmpty())
{
Object o = collection.get();
collection.next()
//...
2. for (int i = 0; i < array.length; i++)
//...
在 C#中:
1.foreach (object o in collection)
//...
2.foreach (int i in array)
//...
C#的for循環(huán)將工作于集合對(duì)象上(數(shù)組實(shí)現(xiàn)一個(gè)集合)。集合對(duì)象有一個(gè)GetEnumerator()方法,該方法返回一個(gè)Enumerator對(duì)象。Enumerator對(duì)象有一個(gè)MoveNext()方法和一個(gè)Current屬性。
8.結(jié)構(gòu)
 把C#的結(jié)構(gòu)視為使語(yǔ)言的類型系統(tǒng)更為優(yōu)雅而不僅是一種“如果你需要的話可以利用之寫出真正有效率的代碼”的概念更好些。
 在C++中,結(jié)構(gòu)和類(對(duì)象)都可分配在棧或堆上。在C#中,結(jié)構(gòu)永遠(yuǎn)創(chuàng)建在棧上,類(對(duì)象)則永遠(yuǎn)創(chuàng)建在堆上。使用結(jié)構(gòu)實(shí)際上可以生成更有效率的代碼:
public struct Vector
{
public float direction;
public int magnitude;
}
Vector[] vectors = new Vector [1000];
這將把1000個(gè)Vector分配在一塊空間上,這比我們把Vector聲明為類并使用for循環(huán)去實(shí)例化1000個(gè)獨(dú)立的Vector來(lái)得有效率得多!咀g注:因懷疑原文有誤,此處故意漏譯一句,但不應(yīng)影響你對(duì)這節(jié)內(nèi)容的理解】:
int[] ints = new ints[1000];//【譯注:此處代碼有誤,應(yīng)為int[] ints = new int[1000];】
C#完全允許你擴(kuò)展內(nèi)建在語(yǔ)言中的基本類型集。實(shí)際上,C#所有的基本類型都以結(jié)構(gòu)方式實(shí)現(xiàn)的。int型只不過(guò)是System.Int32結(jié)構(gòu)的別名,long型不過(guò)是System.Int64結(jié)構(gòu)的別名等等。這些基本類型當(dāng)然可被編譯器特別處理,但是語(yǔ)言本身并無(wú)區(qū)別【譯注:意思是語(yǔ)言自身對(duì)處理所有類型提供了一致的方法】。在下一節(jié)中,我們可看到C#是如何做到這一點(diǎn)的。
9.類型一致
 大多數(shù)語(yǔ)言都有基本類型(int、long等等)。高級(jí)類型最終是由基本類型構(gòu)成的。能以同樣的方式處理基本類型和高級(jí)類型通常來(lái)說(shuō)是有用處的。例如,如果集合可以象包容sting那樣包容int是有用的。為此,Smalltalk通過(guò)犧牲些許效率象處理string或Form一樣來(lái)處理int和long。Java試圖避免這個(gè)效率損失,它象C和C++那樣處理基本類型,但又為每一個(gè)基本類型提供了相應(yīng)的包裝類—int包裝為Integer,double包裝為Double。C++模板參數(shù)可接受任何類型,只要該類型提供了模板定義的操作的實(shí)現(xiàn)。
【譯注:在Java中,你可以這么寫:
int i = 1;
double d = 1.1;
Integer iObj = new Integer(1);
Double dObj = new Double(1.1);
以下寫法是錯(cuò)誤的:
int I = new int(1);
Integer iObj = 1;

C#對(duì)該問(wèn)題提供了一個(gè)不同的解決方案。在上一節(jié)里,我介紹了C#中的結(jié)構(gòu),指出基本類型不過(guò)是結(jié)構(gòu)的一個(gè)別名而已。既然結(jié)構(gòu)擁有所有對(duì)象類型擁有的方法,那代碼就可以這么寫:
int i = 5;
System.Console.WriteLine (i.ToString());
如果我們想象使用一個(gè)對(duì)象那樣使用一個(gè)結(jié)構(gòu),C#將為你裝箱該結(jié)構(gòu)為對(duì)象,當(dāng)你再次需要使用結(jié)構(gòu)時(shí),可以通過(guò)拆箱實(shí)現(xiàn):
Stack stack = new Stack ();
stack.Push (i); // 裝箱
int j = (int) stack.Pop(); //拆箱
拆箱不僅是類型轉(zhuǎn)換的需要,它也是一個(gè)無(wú)縫處理結(jié)構(gòu)和類之間關(guān)系的方式。你要清楚裝箱是做了創(chuàng)建包裝類的工作,盡管CLR可以為被裝箱的對(duì)象提供附加的優(yōu)化。
【譯注:可以這么認(rèn)為,在C#中,對(duì)于任何值(結(jié)構(gòu))類型,都存在如下的包裝類:
class T_Box //T代表任何值類型
{
T Value;
T_Box(T t){Value = t;}
}
當(dāng)裝箱時(shí),比如:
int n = 1;
object box = n;
概念上相當(dāng)于:
int n = 1;
object box = new int_Box(i);
當(dāng)拆箱時(shí),比如:
object box = 1;
int n = (int)box;
概念上相當(dāng)于:
object box = new int_Box(1);
int n = ((int_Box)box).Value;】
【作者注:C#的設(shè)計(jì)者在設(shè)計(jì)過(guò)程中應(yīng)該考慮過(guò)模板。我懷疑未采用模板有兩個(gè)原因:第一個(gè)是混亂,模板可能很難和面向?qū)ο蟮奶匦匀诤显谝黄,它為程序員的帶來(lái)了太多的(混亂)設(shè)計(jì)可能性,而且它很難和反射一起工作;第二點(diǎn)是,如果.NET庫(kù)(例如集合類)沒(méi)有使用模板的話,模板將不會(huì)太有用。不過(guò),果真.NET類使用了它們,那將有20多種使用.NET類的語(yǔ)言不得不也要能和模板一起工作,這在技術(shù)上是非常難以實(shí)現(xiàn)的。
注意到模板(泛型)已經(jīng)被Java社團(tuán)考慮納入Java語(yǔ)言規(guī)范之中是一件有意思的事;蛟S每個(gè)公司都會(huì)各唱各的調(diào)—Sun說(shuō)“.NET患了最小公分母綜合癥”,而微軟則說(shuō)“Java不支持多語(yǔ)言”。
(8月10日致歉)看了一個(gè)對(duì)Anders Hejlsberg的專訪后(windows.oreilly.com/news/hejlsberg_0800.html" target=_blank>http://windows.oreilly.com/news/hejlsberg_0800.html),感覺(jué)似乎模板已浮出地平線,但第一版沒(méi)有,正因我們上面提到的種種困難?吹絀L規(guī)范是如此寫法使得IL碼可以展現(xiàn)模板(用一個(gè)非破壞的方式以讓反射可以很好的工作)而字節(jié)碼則不可以是一件很有趣的事。在此,我還給出了一個(gè)關(guān)于Java社團(tuán)考慮要加入泛型的鏈接:http://jcp.org/jsr/detail/014.jsp 】
【譯注:此處是上文提到的對(duì)Anders Hejlsberg采訪的中文版鏈接:http://www.csdn.net/develop/article/11/11580.shtm。另外,如欲了解更多關(guān)于泛型編程知識(shí),請(qǐng)參見(jiàn)此處鏈接:http://www.csdn.net/develop/article/11/11440