C#

C#

C#(讀做C sharp)是微軟公司發布的一種面向對象的於.NETFramework之上的高級程式設計語言,並定於在微軟職業開發者論壇(PDC)上登台亮相。C#是微軟公司研究員AndersHejlsberg的最新成果。C#看起來Java有著驚人的相似;它包括了諸如單一繼承,界面,與Java幾乎同樣的語法,和編譯成中間代碼再運行的過程。但是C#與Java有著明顯的不同,它借鑑了Delphi的一個特點,與COM(組件對象模型)是直接集成的,而且它是微軟公司。NETwindows網路框架的主角。

基本信息

基本概述

C#它和Java的不同,而不是相似的地方。這一節講述了C#實現的和Java不同的地方或者Java根本沒有的特點。

中間代碼:微軟在用戶選擇何時MSIL應該編譯成機器碼的時候是留了很大的餘地。微軟公司很小心的聲稱MSIL不是解釋性的,而是被編譯成了機器碼。它也明白許多--如果不是大多數的話--程式設計師認為Java程式要不可避免的比C編寫的任何東西都要慢。而這種實現方式決定了基於MSIL的程式(指的是用C#,VisualBasic,“ManagedC ”——C 的一個符合CLS的版本——等語言編寫的程式)將在性能上超過“解釋性的”Java代碼。當然,這一點還需要得到事實證明,因為C#和其他生成MSIL的編譯器還沒有發布。但是JavaJIT編譯器的普遍存在使得Java和C#在性能上相對相同。象C#是編譯語言而Java是解釋性的,之類的聲明只是商業技巧。Java的中間代碼和MSIL都是中間的彙編形式的語言,它們在運行時或其它的時候被編譯成機器代碼。

C#C#

命名空間中的申明:當你創建一個程式的時候,你在一個命名空間裡創建了一個或多個類。同在這個命名空間裡(在類的外面)你還有可能聲明界面,枚舉類型和結構體。必須使用using關鍵字來引用其他命名空間的內容。

基本的數據類型:C#擁有比C,C 或者Java更廣泛的數據類型。這些類型是bool,byte,ubyte,short,ushort,int,uint,long,ulong,float,double,和decimal。象Java一樣,所有這些類型都有一個固定的大小。又象C和C 一樣,每個數據類型都有有符號和無符號兩種類型。與Java相同的是,一個字元變數包含的是一個16位的Unicode字元。C#新的數據類型是decimal數據類型,對於貨幣數據,它能存放28位10進制數字。

兩個基本類:一個名叫object的類是所有其他類的基類。而一個名叫string的類也象object一樣是這個語言的一部分。作為語言的一部分存在意味著編譯器有可能使用它--無論何時你在程式中寫入一句帶引號的字元串,編譯器會創建一個string對象來保存它。

參數傳遞:方法可以被聲明接受可變數目的參數。預設的參數傳遞方法是對基本數據類型進行值傳遞。ref關鍵字可以用來強迫一個變數通過引用傳遞,這使得一個變數可以接受一個返回值。out關鍵字也能聲明引用傳遞過程,與ref不同的地方是,它指明這個參數並不需要初始值。

C#C#

與COM的集成:C#對Windows程式最大的賣點可能就是它與COM的無縫集成了,COM就是微軟的Win32組件技術。實際上,最終有可能在任何。NET語言裡編寫COM客戶和伺服器端。C#編寫的類可以子類化一個以存在的COM組件;生成的類也能被作為一個COM組件使用,然後又能使用,比方說,JScript語言子類化它從而得到第三個COM組件。這種現象的結果是導致了一個運行環境的產生,在這個環境裡的組件是網路服務,可用用任何。NET語言子類化。

歷史發展

C#C#
C#起點高、發展快的新一代語言,它的這五年走過了很多前輩十幾年的路。公允地說,C#是兼顧系統開發和套用開發的最佳實用語言,並且很有可能成為程式語言歷史上的第一個“全能”型語言。看過這篇簡史,我們都應該明白,不要再把C#看成年輕後生了——只要是“馬拉多納”,就早晚當“球王”。C#1.0,純粹的面向對象。當時間回溯到1998年底,微軟正在忙於新一代COM的設計工作。此前,COM一直是組件化開發中非常成功的一種技術;但由於它僅提供了二進制層面上的統一,因此無法將類型信息和用於支持基礎平台和開發工具的信息放到組件中。這時,Java正在逐步走向成熟。

微軟學習Java的做法,將虛擬機的概念引入到了COM領域;同時,微軟提出了“元數據”的概念,用於描述組件的類型信息和工具支持信息,並決定將其放入到組件當中。這種“COM虛擬機”的名字在經歷了若干爭論後,最終被定為CLR(CommonLanguageRuntime,公共語言運行時)。與此同時,微軟提出了在該運行時上運作的語言應該遵循的一些規則,以及該虛擬機的類型系統和指令集——所有這些規範形成了最終的CLI(CommonLanguageInfrastructure,公共語言基礎設施),並提交給了ECMA委員會。同時,微軟開發了CLI的一個實現,這就是大名鼎鼎的.NET了。

1998年12月,微軟啟動了一個全新的語言項目——COOL,這是一款專門為CLR設計的純面向對象的語言,也正是本文的主角——C#的前身。歷時半年有餘,1999年7月份,微軟完成了COOL語言的一個內部版本。直到2000年2月份,微軟才正式將COOL語言更名為C#。據說起這個名字是因為C#開發小組的人很討厭搜尋引擎,因此把大部分搜尋引擎無法識別的“#”字元作為該語言名字的一部分;還有一種說法是在音樂當中“#”是升調記號,表達了微軟希望它在C的基礎上更上一層樓的美好願望——當然這些都只是傳說,無從考證。又是歷經了一系列的修改,微軟終於在2000年7月發布了C#語言的第一個預覽版。

正式發布

C#C#
人們一般認為C#是2000年發布的,並以此來計算它的“年齡”。在此後的一年多時間裡,微軟一直在修補各個測試版本中的BUG。直到2002年2月,微軟終於推出了遲遲未上市的VisualStudio7.0,並將其定名為“VisualStudio.NET2002”。隨著這套開發環境的出爐,開發者們終於看到了C#語言的第一個正式版本——C#1.0。此後,微軟馬不停蹄,VisualStudio也恢復了往日的開發進度。在2003年5月,微軟如期推出了VisualStudio。NET2003,同時也發布了C#的改進版本——C#1.1。這一時期的C#(以下稱為C#1.x)提出了純粹的面向對象概念,並在語言特性中展現得淋漓盡致。C 並非純面向對象的,為了和C兼容以及提供更高的執行效率,它保留了很多模組化的東西。

Java儘管號稱是面向對象的,但實際上,對於對象所應該具備的三種構成結構——屬性、方法和事件,Java僅提供了方法,其它兩種結構都要通過方法來模擬。在C#1.x中,所有面向對象的概念都在語言中得到了非常好的體現。同時,C#還通過類類型、值類型和接口類型的概念形成了統一的類型系統。C#使用了大家所熟知的語法實現了方法,以至於很多人認為C#和Java、C 等面向對象語言“非常相像”,這使得從使用其他面向對象語言轉到使用C#的過程非常簡單。此外,C#還通過無參數列表的方法聲名語法,結合get/set訪問器實現了優雅的屬性語法。

get訪問器相當於獲取屬性值的方法,可以通過一些運算返回最終的結果,而不是簡單地返回一個變數的值;而set訪問器相當於設定屬性值的方法,在其中可以進行一系列檢測,最後將屬性值賦給相應的變數。同時,通過同時提供get和set訪問器、只提供get訪問器和只提供set訪問器,還可以很方便地實現可寫、唯讀和只寫的屬性。C#的這種屬性語法,使得一個屬性在提供該屬性的類的內部看來,非常像一組方法;而對於外部調用類看來,訪問一個對象的屬性和訪問它的公共域沒有任何區別。通過委託,結合關鍵字event,C#提供了優雅的事件概念。

訪問計算

C#C#
使用 =運算符,開發者可以非常方便地將一個事件處理器關聯到一個事件上,這個過程稱之為“訂閱”一個事件。由於委託內部封裝了一個調用鍊表,因此可以方便地為一個事件添加多個事件處理器,這些處理器會自動地依次調用。多年的開發語言進化證明,函式指針是非常重要也是非常危險的語言特徵之一。同時,基於函式指針的回調機制也Windows核心概念之一。然而,由於函式指針很難驗證參數的類型準確性,因此C#(確切地說是CLI)提出了“委託”的概念,這是一種類型安全的函式指針鍊表。這意味著,C#不僅可以提供回調機制,同時調用回調的一方還無需在其內部維護函式指針列表,所要做的僅僅是聲名一個具有恰當委託類型的公共成員即可;而提供回調的一方也只需通過構造一個帶有指定方法的相應委託實例,並通過“ =”運算符添加到回調列表即可。

儘管C#1.x提供了如此多的新鮮概念,但實際上,這些概念都是由CLI提出的。因此當將一個C#源程式編譯為執行檔時,編譯器做的工作相對而言並不多。需要編譯器代勞的是要將一個簡單的委託定義語句翻譯為一個繼承System.MulticastDelegate類型定義。
C#2.0,泛型編程新概念

微軟本打算繼續保證開發進度,並在2004年推出VisualStudio。NET2004,但由於其間軟體工程學尤其是軟體管理學的大規模進步,微軟所提供的這種僅具備開發和調試功能的IDE已經無法滿足團隊開發的需求。因此微軟決定在項目設計和管理工具方面進行了進一步研發,並將其集成到VisualStudio中,以贏回原有的市場。因此,微軟將VisualStudio。NET2004“改名”為VisualStudio2005,並決定推遲一年發布。不過,微軟還是堅持在2004年的6月份發布了VisualStudio2005的第一個Beta版,同時向開發者展示了C#語言的2.0版本。

2005年4月,微軟發布了VisualStudio2005Beta2,這已經是具備了幾乎全部功能的VisualStudio,包括的產品有SQLServer2005、TeamFoundationServer和TeamSuite。這時的C#編譯器已經能夠處理C#2.0中所有的新特性。C#2.0為開發者帶來的最主要的特性就是泛型編程能力。和面向對象思想一樣,泛型思想也是一種已經成熟的編程思想,但依然是沒有哪一種主流開發語言能夠支持完備的泛型概念。這主要是因為泛型的概念在一定程度上對面向對象概念進行衝擊,同時,由於在編譯期間對類型參數的完全檢測很難做到,很多問題會被遺留到運行時。C#2.0別出心裁,對泛型類型參數提出了“約束”的新概念,並以優雅的語法體現在語言之中。有了約束,結合編譯器強大的類型推斷能力,可以在編譯時發現幾乎所有“危險”的泛型套用。

C#2.0的另一個突出的特性就是匿名方法,用來取代一些短小的並且僅出現一次的委託,使得語言結構更加緊湊。匿名方法除了可以使得事件處理器的編寫更加精簡以外,還將開發者帶入了程式設計的一個新的領域——函式式編程,曾經有高人就用匿名方法結合泛型編程實現了函式式編程中的重要結構——Lambda表達式。儘管這種實現顯得很繁瑣而且不易理解,但畢竟是實現了。最終,函式式編程還是被引入到了C#語言中,這將在下一節中為大家講述。

C#2.0還進一步增強了語言的表達能力。在C#2.0中,屬性語法中的get和set訪問器可以擁有不同的許可權,這就使得定義一個在庫的內部可讀寫,而在庫的外部唯讀的屬性成為可能。同時,C#2.0還提供了疊代器的概念,這使得一個類無需實現IEnumerator和IEnumerable接口即可實現一個可以進行遍歷的類型,並且無需在類型中維護疊代狀態。此時的.NET已經得到了很廣泛的認可,並且因為元數據為組件帶來了強大的自我描述能力,許多程式庫廠商被吸引到.NET平台上來。

程式的執行

C#並不被編譯成為能夠直接在計算機上執行的二進制本地代碼。與Java類似,它被編譯成為中間代碼(Microsoft Intermediate Language),然後通過.NET Framework的虛擬機——被稱之為通用語言運行時.NET CLR(Common Language Runtime)——執行。

所有的.Net程式語言都被編譯成這種被稱為MSIL(Microsoft Intermediate Language )的中間代碼。因此雖然最終的程式在表面上仍然與傳統意義上的執行檔都具有“.exe”的後綴名。但是實際上,如果計算機上沒有安裝.Net Framework,那么這些程式將不能夠被執行。

在程式執行時,.Net Framework將中間代碼翻譯成為二進制機器碼,從而使它得到正確的運行。最終的二進制代碼被存儲在一個緩衝區(Buffer)中。所以一旦程式使用了相同的代碼,那么將會調用緩衝區中的版本。這樣如果一個.Net程式第二次被運行,那么這種翻譯不需要進行第二次,速度明顯加快。

程式修訂

C#C#
.NET程式庫數量的增長,逐漸暴露了命名的問題。在面向對象技術廣泛發展後,人們就意識到名字的管理問題,因此幾乎所有的面向對象語言都提出了“命名空間”的概念;而在C#1.x時代,這個問題再一次出現。如果一個庫廠商XX希望以XX.System來命名他們自己的系統基礎庫,那么當開發者使用usingSystem語句時就會產生歧義。為此。C#2.0中提供了global關鍵字,這為。NET庫中所有的命名空間提供了一個“根”,通過指定global::System和global::XX。System就可以區別兩個庫了。這一時期的C#編譯器變得非常複雜,泛型的引入使得編譯器不得不具備超強的類型推斷能力。同時,疊代器的思想並非是在CLI層面上實現的,而是由編譯器自動生成了實現IEnumerator和IEnumerable接口類型。C#3.0,魔鬼在經歷了一系列的改進和完善後,微軟決定於2005年11月發布VisualStudio2005,該開發環境將正式支持C#2.0。由於此推出了數個預覽版和測試版,大家的期待之情似乎已經不是那么強烈了。而2005年9月份的PDC大會則為開發者們帶來了另外的驚喜——C#3.0(研發代號“Orcas”——魔鬼)的技術預覽版。

C#3。0,就不得不提一下微軟的LINQ項目,LINQ(語言集成查詢,LanguageIntegratedQuery)提出了一種通過面向對象語法來實現對非面向對象數據源的查詢技術,可查詢的數據源從關係型資料庫延伸到一般意義上的集合(如數組和列表)以及XML。而C#3。0則是率先實現了LINQ的語言。在C#3。0中,我們可以用類似於SQL語句的語法從一個數據源中輕鬆地得到滿足一定條件的對象集合。

例如要查找一個字元串數組names中所有長度大於5的字元串,就可以寫:varlongname=fromninnameswheren。Length>5selectn;這樣就得到一個新的字元數組longname,其中包含了所需要的結果。這種語句稱作查詢語句,與SQL語句唯一的區別是C#中的查詢語句往往把select子句放到最後(這反而倒有些類似於中文的閱讀順序了)

C#編譯器並不會對這種語法進行實際的的編譯,而是將其翻譯為正常的方法調用:varlongname=names。Where(n=>n。Length>5)。Select(n);然後再進行進一步的編譯。在上面的例子中已經說明,names是一個存放有字元串的數組,而數組類型並沒有Where的方法。的確,Where並非names的成員方法,微軟也沒有對數組類型進行任何改動。

擴展方法

C#C#
擴展方法是定義在其他靜態類中的靜態方法,其第一個參數的類型就是希望擴展的類型,並且這個參數被冠以this修飾符。擴展方法是靜態的,但可以像調用被擴展類型的實例方法那樣進行調用,看起來好像是被擴展類型自己的方法一樣。這就為語言帶來了很大的靈活性,我們可以將一組近似的功能如上面的Where和Select等(這在LINQ中被稱作“標準查詢表達式”)定義在一個外部類中,這樣既無須修改現有類型,又可以將功能組織在一起。

為了做到面向對象的封裝性,擴展方法只能在被擴展類型的公共成員上進行操作,如果需要從內部對類型進行改進,就必須改變現有類型的代碼。在Where方法的參數列表里,我們又發現了一種奇怪的語法:n=>n。Length>5。這就是我們上文提到過的Lambda表達式。微軟的官方規範中稱,Lambda表達式是匿名方法的一種自然進化。因此Lambda表達式其實也是一種特殊的委託,由編譯器負責生成一個匿名的委託類型,它接受一個字元串類型的參數n;返回值為布爾類型,表示n的長度是否大於5;其中的參數類型和返回值類型都是由編譯器推斷而來的。說到類型推斷,還要解釋的一點就是上面的語句中出現的新關鍵字var。

從出現的位置來看,var應該是一個類型。然而這又不是一個C#內建類型,也不是CLI提出的新類型;它只是一個“占位符”,它的確表示一個類型,但具體是什麼類型需要編譯器在編譯期間進行推斷。Lamda表達式的真正意義不僅僅在於簡化了委託的編寫方式,更重要的是它把代碼表達式體現為了數據。換句話說,Lambda表達式不僅可以被編譯為一段可以執行的代碼(類似於匿名方法),也可以將其翻譯為一個數據結構——表達式樹。而如何處理Lambda表達式,是由編譯器根據Lambda表達式的使用方式來自動確定的。

當把一個Lambda表達式賦給一個具有委託類型的域、屬性或變數時,編譯器像編譯匿名方法一樣將表達式體翻譯成一段可執行代碼;而當把一個Lambda表達式賦給一個具有Expression類型的域、屬性或變數時,編譯器就會將Lambda表達式解析為一個表達式樹。對於翻譯為代碼的Lambda,可以向調用委託那樣進行調用,而對於翻譯為表達式樹的Lambda表達式,就不可以了,會得到一個編譯錯誤。但表達式樹存在於一個由編譯器生成的數據結構中,因此可以在運行時對其進行分析甚至修改。除了上面提到的一些重大改進之外,

C#3.0也對細微的語法進行了一些改進,使C#語言變得更加優雅和全面。值得說明的是,C#3.0經過編譯後生成的IL代碼,完全是基於。NET2.0的,C#語言已經遠遠跑在了他所棲生的平台前面。這一時期的C#語言離CLI已經越來越遠了,編譯器的工作也愈加繁重起來。首先很多語言結構(如查詢表達式和Lambda表達式)都不是CLI中提供的特性,因此需要編譯器進行大量的轉譯工作;其次是這些語言結構帶來的大量類型推斷任務,也都是靠編譯器來完成的。

C#走到了3.0以後,已經完全不再是當年那個“簡單”的語言了。它的開發者稱其為“魔鬼”,而琳琅滿目的新特性也的確讓開發者們眼花繚亂,甚至感到恐懼。語言集成查詢的引入,使得前一段時期內為開發者們廣泛討論的ORM概念得到了更加深入地體現,尤其是它所支持的數據源之廣泛,讓ORM理念變得已經不再必要了;而一些“。NET中的ORM實現”,似乎也成了完全不必要的擴展項目了。Lambda表達式的引入,使得C#將可以輕鬆地完成特定領域(Domain-Specific)的開發。

相關詞條

相關詞條

相關搜尋

熱門詞條

聯絡我們