【教程】【轉載】C#銳利體驗(李建忠)—01

來源:互聯網
上載者:User
教程 C#銳利體驗
南京郵電學院 李建忠(cornyfield@263.net)

C#語言是一門簡單,現代,優雅,物件導向,型別安全,平台獨立的一門新型組件程式設計語言。其文法風格源自C/C++家族,融合了Visual Basic的高效和C/C++強大,是微軟為奠定其下一互連網霸主地位而打造的Microsoft.Net平台的主流語言。其一經推出便以其強大的操作能力,優雅的文法風格,創新的語言特性,第一等的面向組件編程的支援而深受世界各地程式員的好評和喜愛。“它就是我多年來夢寐以求的電腦語言!”--很多資深程式員拿到C#都是這樣的驚訝。從C#語言的名字(C Sharp)我們也可見微軟用其打造其下一代互連網絡深度服務的勃勃雄心。C#語言目前已由微軟提交歐洲電腦製造商協會ECMA,經過標準化後的C#將可由任何廠商在任何平台上實現其開發工具及其支援軟體,這為C#的發展提供了強大的驅動力,我們也可從這裡看到微軟前所未有的眼光和智慧。組件編程已經成為當今世界軟體業面向下一代程式開發的一致選擇,是90年代物件導向編程的深度發展。C#生逢其時,佔盡天時地利,“第一等的面向組件編程的支援”也決不是簡單說說那麼輕鬆。實際上,組件特性已經深深植入C#語言的各個層面,是為C#銳利(Sharp)之處。在下面的文章中筆者將從C#語言的各個層面來展現C#語言中無處不見的組件特性,深度闡述C#面向組件編程。整個專題共分為十講:“第一講 ‘Hello,World!’程式”,“第二講 C#語言基礎介紹”,“第三講 Microsoft.NET平台基礎構造”,“第四講 類 結構與枚舉”,“第五講 構造器與析構器”,“第六講 域 方法 屬性與索引器”,“第七講 介面 繼承與多態”,“第八講 委派與事件”,“第九講 數組與字串”,“第十講 特徵與映射”,“第十一講 COM互操作 非託管編程與異常處理”,“第十二講 用C#編織未來--C#編程模型概述”。第一講 “Hello,World!”程式“Hello World!”程式是程式員一直以來的一個浪漫約定,也是一個偉大的夢想--總有一天,出自人類之手的電腦會面對這個美麗的世界說一聲“Hello World!”。它是學習一門新語言的一個很好的起點,我們就從這裡開始,看下面例子:
//HelloWorld.cs by Cornfield,2001
//csc HelloWorld.cs
using System;
class HelloWorld
{
    public static void Main()
    {
        Console.WriteLine("Hello World !");
    }
}
我們可以開啟Windows內建的簡易的"記事本"程式來編寫這段代碼--筆者推薦剛開始採用這個極其簡單卻能把程式碼暴露的相當清晰的編輯工具。我們將它的檔案名稱儲存為HelloWorld.cs,其中".cs"是C#原始碼檔案的副檔名。然後在配置好C#編譯器的命令列環境裡鍵入"csc HelloWorld.cs"編譯檔案。可以看到編譯輸出檔案HelloWorld.exe。我們鍵入HelloWorld執行這個檔案可得到下面的輸出:Hello World !下面我們來仔細分析上面的代碼和整個程式的編譯輸出及執行過程。先看檔案開始的兩行代碼,這是C#語言的單行備註陳述式。和C++語言類似,C#支援兩種注釋方法:以"//"開始的單行注釋和以"/*","*/"配對使用的多行注釋。注釋之間不能嵌套。再來看下面的"using System;"語句,這是C#語言的using命名空間指示符,這裡的"System"是Microsoft.NET系統提供的類庫。C#語言沒有自己的語言類庫,它直接擷取Microsoft.NET系統類別庫。Microsoft.NET類庫為我們的編程提供了非常強大的通用功能。該語句使得我們可以用簡短的別名"Console"來代替類型"System.Console"。當然using指示符並不是必須的,我們可以用類型的全域名字來擷取類型。實際上,using語句採用與否根本不會對C#編譯輸出的程式有任何影響,它僅僅是簡化了較長的命名空間的類型引用方式。接著我們聲明並實現了一個含有靜態Main()函數的HelloWorld類。C#所有的聲明和實現都要放在同一個檔案裡,不像C++那樣可以將兩者分離。Main()函數在C#裡非常特殊,它是編譯器規定的所有可執行程式的進入點。由於其特殊性,對Main()函數我們有以下幾條準則:Main()函數必須封裝在類或結構裡來提供可執行程式的進入點。C#採用了完全的物件導向的編程方式,C#中不可以有像C++那樣的全域函數。Main()函數必須為靜態函數(static)。這允許C#不必建立執行個體對象即可運行程式。Main()函數保護層級沒有特殊要求, public,protected,private等都可,但一般我們都指定其為public。Main()函數名的第一個字母要大寫,否則將不具有進入點的語義。C#是大小寫敏感的語言。Main()函數的參數只有兩種參數形式:無參數和string 數組表示的命令列參數,即static void Main()或static void Main(string[]args) ,後者接受命令列參數。一個C#程式中只能有一個Main()函數進入點。其他形式的參數不具有進入點語義,C#不推薦通過其他參數形式重載Main()函數,這會引起編譯警告。Main()函數傳回值只能為void(無類型)或int(整數類型)。其他形式的傳回值不具有進入點語義。我們再來看"HelloWorld.cs"程式中Main()函數的內部實現。前面提過,Console是在命名空間System下的一個類,它表示我們通常打交道的控制台。而我們這裡是調用其靜態方法WriteLine()。如同C++一樣,靜態方法允許我們直接作用於類而非執行個體對象。WriteLine()函數接受字串類型的參數"Hello World !",並把它送入控制台顯示。如前所述,C#沒有自己的語言類庫,它直接擷取Microsoft.NET系統類別庫。我們這裡正是通過擷取Microsoft.NET系統類別庫中的System.Console.WriteLine()來完成我們想要的控制台輸出操作。這樣我們便完成了"Hello World!"程式。但事情遠沒那麼簡單!在我們編譯輸出執行程式的同時,Microsoft.NET底層的諸多機制卻在暗地裡湧動,要想體驗C#的銳利,我們沒有理由忽視其背靠的Microsoft.NET平台。實際上如果沒有Microsoft.NET平台,我們很難再說C#有何銳利之處。我們先來看我們對"HelloWorld.cs"檔案用csc.exe命令編譯後發生了什麼。是的,我們得到了HelloWorld.exe檔案。但那僅僅是事情的表象,實際上那個HelloWorld.exe根本不是一個可執行檔!那它是什嗎?又為什麼能夠執行?好的,下面正是回答這些問題的地方。首先,編譯輸出的HelloWorld.exe是一個由中繼語言(IL),中繼資料(Metadata)和一個額外的被編譯器添加的目標平台的標準可執行檔頭(比如Win32平台就是加了一個標準Win32可執行檔頭)組成的PE(portable executable,可移植執行體)檔案,而不是傳統的二進位可執行檔--雖然他們有著相同的副檔名。中繼語言是一組獨立於CPU的指令集,它可以被即時編譯器Jitter翻譯成目標平台的本地代碼。中繼語言代碼使得所有Microsoft.NET平台的進階語言C#,VB.NET,VC.NET等得以平台獨立,以及語言之間實現互操作。中繼資料是一個內嵌於PE檔案的表的集合。中繼資料描述了代碼中的資料類型等一些通用語言運行時(Common Language Runtime)需要在代碼執行時知道的資訊。中繼資料使得.NET應用程式代碼具備自描述特性,提供了型別安全保障,這在以前需要額外的類型庫或介面定義語言(Interface Definition Language,簡稱IDL)。這樣的解釋可能還是有點讓人困惑,那麼我們來實際的解剖一下這個PE檔案。我們採用的工具是.NET SDK Beta2內建的ildasm.exe,它可以協助我們提取PE檔案中的有關資料。我們鍵入命令"ildasm /output:HelloWorld.il HelloWorld.exe",一般可以得到兩個輸出檔案:helloworld.il和helloworld.res。其中後者是提取的資源檔,我們暫且不管,我們來看helloworld.il檔案。我們用"記事本"程式開啟可以看到中繼資料和中繼語言(IL)代碼,由於篇幅關係,我們只將其中的中繼語言代碼提取出來列於下面,有關中繼資料的表項我們暫且不談:class private auto ansi beforefieldinit HelloWorld
       extends [mscorlib]System.Object
{
  .method public hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "Hello World !"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method HelloWorld::Main

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method HelloWorld::.ctor

} // end of class HelloWorld

我們粗略的感受是它很類似於早先的組合語言,但它具有了對象定義和操作的功能。我們可以看到它定義並實現了一個繼承自System.Object 的HelloWorld類及兩個函數:Main()和.ctor()。其中.ctor()是HelloWorld類的建構函式,可在"HelloWorld.cs"原始碼中我們並沒有定義建構函式呀--是的,我們沒有定義建構函式,但C#的編譯器為我們添加了它。你還可以看到C#編譯器也強制HelloWorld類繼承System.Object類,雖然這個我們也沒有指定。關於這些進階話題我們將在以後的講座中予以剖析。那麼PE檔案是怎麼執行的呢?下面是一個典型的C#/.NET應用程式的執行過程:使用者執行編譯器輸出的應用程式(PE檔案),作業系統載入PE檔案,以及其他的DLL(.NET動態串連庫)。作業系統裝載器根據前面PE檔案中的可執行檔頭跳轉到程式的進入點。顯然,作業系統並不能執行中繼語言,該進入點也被設計為跳轉到mscoree.dll(.NET平台的核心支援DLL)的_ CorExeMain()函數入口。CorExeMain()函數開始執行PE檔案中的中繼語言代碼。這裡的執行的意思是通用語言運行時按照調用的對象方法為單位,用即時編譯器將中繼語言編譯成本地機二進位代碼,執行並根據需要存於機器緩衝。程式的執行過程中,垃圾收集器負責記憶體的分配,釋放等管理功能。
程式執行完畢,作業系統卸載應用程式。
清楚的知曉編譯輸出的PE檔案的執行過程是深度掌握C#語言編程的關鍵,這種過程的本身就詮釋著C#語言的進階核心機制以及其背後Microsoft.NET平台種種詭秘的性質。一個"Hello World !"程式的概括力已經足夠,在我們對C#語言有了一個很好的起點之後,下面的專題會和大家一起領略C#基礎語言,窺探Microsoft.NET平台構造,步步體驗C#銳利編程的極樂世界,Let's go! 

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

11.11 Big Sale for Cloud

Get Unbeatable Offers with up to 90% Off,Oct.24-Nov.13 (UTC+8)

Get It Now >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。