文章目錄
- 資料類型
- 變數與常量
- 操作符與運算式
- 命名空間與語句
閱讀http://www.microsoft.com/china/msdn/library/langtool/vcsharp/cornyfield.mspx
C#銳利體驗發布日期: 2/4/2002 | 更新日期: 6/22/2004
南京郵電學院 李建忠(jzli@china.com)
的一點筆記:
第一講 “Hello,World!”程式
//HelloWorld.cs by Cornfield,2001//csc HelloWorld.csusing System;class HelloWorld{public static void Main(){Console.WriteLine("Hello World !");}}C#支援兩種注釋方法:以"//"開始的單行注釋和以"/*","*/"配對使用的多行
注釋。注釋之間不能嵌套。
我想應該還有第三種///用於產生文檔,類似JAVA
關於using語句:
當然using指示符並不是必須的,我們可以用類型的全域名字來擷取類型。實際
上,using語句採用與否根本不會對C#編譯輸出的程式有任何影響,它僅僅是簡
化了較長的命名空間的類型引用方式。
C#採用命名空間(namespace)來組織程式。命名空間可以嵌套。using指示符
可以用來簡化命名空間類型的引用。using指示符有兩種用法。
"using System;"語句可以使我們用簡短的類型名"Console"來代替類型
"System.Console"。
"using Output = System.Console;"語句可以使我們用別名"Output"來
代替類型"System.Console"。命名空間的引入大大簡化了C#程式的組織方式。
著我們聲明並實現了一個含有靜態Main()函數的HelloWorld類。C#所有的聲
明和實現都要放在同一個檔案裡,不像C++那樣可以將兩者分離。Main()函數
在C#裡非常特殊,它是編譯器規定的所有可執行程式的進入點。由於其特殊性,
對Main()函數我們有以下幾條準則:
1. |
Main()函數必須封裝在類或結構裡來提供可執行程式的進入點。C#採用了完全的物件導向的編程方式,C#中不可以有像C++那樣的全域函數。 |
2. |
Main()函數必須為靜態函數(static)。這允許C#不必建立執行個體對象即可運行程式。 |
3. |
Main()函數保護層級沒有特殊要求, public,protected,private等都可,但一般我們都指定其為public。(注:當然public第一個字線也不能大寫) |
4. |
Main()函數名的第一個字母要大寫(注:有別於JAVA),否則將不具有進入點的語義。C#是大小寫敏感的語言。 |
5. |
Main()函數的參數只有兩種參數形式:無參數和string 數組表示的命令列參數,即static void Main()或static void Main(string[]args) ,後者接受命令列參數。一個C#程式中只能有一個Main()函數進入點。其他形式的參數不具有進入點語義,C#不推薦通過其他參數形式重載Main()函數,這會引起編譯警告。 |
6. |
Main()函數傳回值只能為void(無類型)或int(整數類型)。其他形式的傳回值不具有進入點語義。 編譯輸出的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)。 鍵入命令"ildasm /output:HelloWorld.il HelloWorld.exe",一般可以得到兩個輸出檔案:helloworld.il和helloworld.res。其中後者是提取的資源檔,我們暫且不管,我們來看helloworld.il檔案。 |
類似於早先的組合語言,但它具有了對象定義和操作的功能。我們可以看到它定義並實現了一個繼承自System.Object 的HelloWorld類及兩個函數:Main()和.ctor()。
第二講 C#語言基礎介紹資料類型
C#語言的資料類型主要分為兩類:實值型別和參考型別。另外一種資料類型"指標"是為unsafe上下文編程專門設定的,其中unsafe上下文指對代碼進行unsafe標示以滿足利用指標對記憶體直接進行操作要求的C#Unmanaged 程式碼,這些代碼將失去Microsoft.NET平台的垃圾收集等CLR性質
null值表示參考型別沒有對任何實際地址進行引用。
實值型別可分為結構類型和枚舉類型。結構類型包括簡單類型和使用者自訂結構類型。簡單類型又可分為布爾類型和數實值型別。C#語言中布爾類型嚴格與數實值型別區分,只有true和false兩種取值,不存在像C/C++裡那樣和其他類型之間的轉換。數實值型別包括整值,浮點和decimal三種類型。整實值型別有sbyte,byte,short,ushort,int,uint,long,ulong,char共九種。除了char類型外,其他8種兩兩一組分別為有符號和無符號兩種。浮點值有float和double兩種。decimal主要用於金融,貨幣等對精度要求比較高的計算環境。下表是對這些簡單類型的一個詳細的描述:
| 簡單類型 |
描 述 |
示 例 |
sbyte |
8-bit 有符號整數 |
sbyte val = 12; |
short |
16-bit 有符號整數 |
short val = 12; |
int |
32-bit有符號整數 |
int val = 12; |
long |
64-bit有符號整數 |
long val1 = 12; long val2 = 34L; |
byte |
8-bit不帶正負號的整數 |
byte val1 = 12; byte val2 = 34U; |
ushort |
16-bit 不帶正負號的整數 |
ushort val1 = 12; ushort val2 = 34U; |
uint |
32-bit 不帶正負號的整數 |
uint val1 = 12; uint val2 = 34U; |
ulong |
64-bit 不帶正負號的整數 |
ulong val1 = 12; ulong val2 = 34U; ulong val3 = 56L; ulong val4 = 78UL; |
float |
32-bit單精確度浮點數 |
float val = 1.23F; |
double |
64-bit雙精確度浮點數 |
double val1 = 1.23; double val2 = 4.56D; |
bool |
布爾類型 |
bool val1 = true; bool val2 = false; |
char |
字元類型 ,Unicode 編碼 |
char val = 'h'; |
decimal |
28個有效數位128-bit十進位類型 |
decimal val = 1.23M; |
參考型別共分四種類型:類,介面,數組,委派。類除了我們可以定義自己的類型外,又包括兩個比較特殊的類型object和string。object是C#中所有類型(包括所有的實值型別和參考型別)的繼承的根類。string類型是一個密封類型(不能被繼承),其執行個體表示Unicode字串,它和數群組類型我們將放在"第九講 結構,枚舉,數組與字串"中詳述。介面類型定義一個方法的合約,我們將在"第七講 介面 繼承與多態"中講述。委派類型是一個指向靜態或執行個體方法的簽名,類似於C/C++中的函數指標,將在"第八講 委派與事件"中講述。實際上我們將從後面的專題中看到這些類型都是類的某種形式的封裝。
每種資料類型都有對應的預設值。數實值型別的預設值為0或0.0,其中char的預設為'/x0000'。布爾類型的預設值為false。枚舉類型的預設值為0。結構類型的預設值是將它所有的實值型別的網域設定為對應實值型別的預設值,將其參考型別的網域設定為null。所有參考型別的預設值為null。
不同類型的資料之間可以轉換,C#的類型轉換有隱含轉換,明晰轉換,標準轉換,自訂轉換共四種方式。隱含轉換與明晰轉換和C++裡一樣,資料從"小類型"到"大類型"的轉換時為隱含轉換,從"大類型"到"小類型"的轉換為明晰轉換,明晰轉換需要如"(Type)data"一般的括弧轉換操作符。標準轉換和自訂轉換是針對系統內建轉換和使用者定義的轉換而言的,兩者都是對類或結構這樣的自訂類型而言的。
變數與常量
變數表示儲存位置,變數必須有確定的資料類型。C#的型別安全的含義之一就是確保變數的儲存位置容納著合適的類型。可以將C#中的變數分為靜態變數,執行個體變數,傳值參數,引用參數,輸出參數,數組參數和本地變數共七種。本地變數則是在方法體內的臨時變數。
靜態變數和執行個體變數主要是針對類或結構內的資料成員(又叫域)而言的。靜態變數在它寄存的類或結構類型被裝載後得到儲存空間,如果沒有對它進行初始化賦值,靜態變數的初始值將是它的類型所持有的預設值。執行個體變數在它的類執行個體被建立後獲得儲存空間,如果沒有經過初始化賦值,它的初始值與靜態變數的定義相同。兩者更詳細的說明我們放在"第六講 域 方法 屬性與索引器"專題裡。
傳值參數,引用參數,輸出參數,數組參數主要針對方法的參數類型而言的。簡單的講傳值參數是對變數的值的一種傳遞,方法內對變數的改變在方法體外不起作用。對於傳值參數本身是引用型的變數稍有不同,方法內對該引用(控制代碼)變數指向的資料成員即實際記憶體塊的改變將在方法體外仍然保留改變,但對於引用(控制代碼)本身的改變不起作用。引用參數是對變數的控制代碼的一種傳遞,方法內對該變數的任何改變都將在方法體外保留。輸出參數是C#專門為有多個傳回值的方法而量身定做的,它類似於引用變數,但可以在進入方法體之前不進行初始化,而其他的參數在進入方法體內C#都要求明確的初始化。數組參數是為傳遞大量的數組元素而專門設計的,它從本質上講是一種引用型變數的傳值參數。它們更詳細的闡述我們也放在"第六講 域 方法 屬性與索引器"專題裡。
本地變數嚴格的講是在C#的塊語句,for語句,switch語句,using語句內聲明的變數,它的生命週期嚴格地被限制在這些語句塊內部。
常量在編譯時間便確定它的值,在整個程式中也不許修改。常量聲明的同時必須賦值。由於它的編譯時間確定值的特性,參考型別可能的值只能為string和null(除string外,參考型別的構建器必須在運行時才能確定參考型別的值)。
操作符與運算式
C#保留了C++所有的操作符,其中指標操作符(*和->)與引用操作符(&)需要有unsafe的上下文。C#擯棄了範圍辨析操作符(::),一律改為單點操作符(.)。我們不再闡述那些保留的C++的操作符,這裡主要介紹C#引入的具有特殊意義的幾個操作符:as,is,new, typeof,sizeof,stackalloc。
as操作符用於執行相容類型之間的轉換,當轉換失敗時,as 操作符結果為null。is 操作符用於檢查對象的運行時類型是否與給定類型相容,當運算式非null且可以轉化為指定類型時,is操作符結果為true,否則為false。as和is操作符是基於同樣的類型鑒別和轉換而設計的,兩者有相似的應用場合。實際上expression as type相當於expression is type ? (type)expression : (type)null。
(以下關於堆與棧分別放置哪種變數的描述)
作為操作符的new用於在堆上建立對象和調用建構函式,值得注意的是實值型別對象(例如結構)是在堆棧上建立的,而參考型別對象(例如類)是在堆上建立的。new也用於修飾符,用於隱藏基類成員的繼承成員。為隱藏繼承的成員,使用相同名稱在衍生類別中聲明該成員並用 new 修飾符修改它。typeof 運算子用於獲得某一類型的 System.Type 對象,我們將在"第十講 特徵與映射"裡結合Microsoft.NET的類型系統對它作詳細的闡述。sizeof 運算子用於獲得實值型別(不適用於參考型別)的大小(以位元組為單位)。stackalloc用於在堆棧上分配記憶體塊, 僅在局部變數的初始值設定項中有效,類似於C/C++語言的_alloca。sizeof和statckalloc都由於涉及記憶體的直接操作而需要unsafe上下文。
C#裡的某些操作符可以像C++裡那樣被重載。操作符重載使得自訂類型(類或結構)可以用簡單的操作符來方便的表達某些常用的操作。
為完成一個計算結果的一系列操作符和運算元的組合稱為運算式。和C++一樣,C#的運算式可以分為賦值運算式和布林運算式兩種,C#沒有引入新的運算式形式,我們對此不再贅述。
命名空間與語句
C#採用命名空間(namespace)來組織程式。命名空間可以嵌套。
C#語句可以分為標號語句,聲明語句,塊語句,空語句,運算式語句,選擇語句,反覆語句,跳躍陳述式,try語句,checked/unchecked語句,lock語句,using語句。
標號語句主要為goto跳轉設計,C#不允許跨方法的跳轉,但允許小規模的方法內的跳轉。聲明語句可以同時進行初始化賦值,對象的執行個體化聲明需要new關鍵字。塊語句採用"{"和"}"定義語句塊,主要是界定局部變數的作用範圍。空語句在C#中用分號";"表示,沒有執行語義。運算式語句通過運算式構成語句。
選擇語句有if語句和switch語句兩種,與C++別無二致。反覆語句除了while,do,for三種迴圈結構外引入了foreach語句用於遍曆集合中所有的元素,但這需要特定的介面支援,我們在後面的章節裡對之作詳細闡述。
跳躍陳述式有break,continue,goto,return,throw五種語句,前四種與C++裡的語義相同,throw語句與後面的try語句我們將在"第十一講 COM互操作 非託管編程與異常處理"闡述。
checked/unchecked語句主要用於數值運算中溢出檢查的上下文。lock語句主要用於線程訊號量的鎖控制。using語句主要用於片斷資源管理。這些我們在後續章節裡都會有具體的涉及。