基本概述
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都是中間的彙編形式的語言,它們在運行時或其它的時候被編譯成機器代碼。

命名空間中的申明:當你創建一個程式的時候,你在一個命名空間裡創建了一個或多個類。同在這個命名空間裡(在類的外面)你還有可能聲明界面,枚舉類型和結構體。必須使用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不同的地方是,它指明這個參數並不需要初始值。

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

微軟學習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#語言的第一個預覽版。
正式發布

Java儘管號稱是面向對象的,但實際上,對於對象所應該具備的三種構成結構——屬性、方法和事件,Java僅提供了方法,其它兩種結構都要通過方法來模擬。在C#1.x中,所有面向對象的概念都在語言中得到了非常好的體現。同時,C#還通過類類型、值類型和接口類型的概念形成了統一的類型系統。C#使用了大家所熟知的語法實現了方法,以至於很多人認為C#和Java、C 等面向對象語言“非常相像”,這使得從使用其他面向對象語言轉到使用C#的過程非常簡單。此外,C#還通過無參數列表的方法聲名語法,結合get/set訪問器實現了優雅的屬性語法。
get訪問器相當於獲取屬性值的方法,可以通過一些運算返回最終的結果,而不是簡單地返回一個變數的值;而set訪問器相當於設定屬性值的方法,在其中可以進行一系列檢測,最後將屬性值賦給相應的變數。同時,通過同時提供get和set訪問器、只提供get訪問器和只提供set訪問器,還可以很方便地實現可寫、唯讀和只寫的屬性。C#的這種屬性語法,使得一個屬性在提供該屬性的類的內部看來,非常像一組方法;而對於外部調用類看來,訪問一個對象的屬性和訪問它的公共域沒有任何區別。通過委託,結合關鍵字event,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#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的成員方法,微軟也沒有對數組類型進行任何改動。
擴展方法

為了做到面向對象的封裝性,擴展方法只能在被擴展類型的公共成員上進行操作,如果需要從內部對類型進行改進,就必須改變現有類型的代碼。在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)的開發。