【教程】【轉載】C#銳利體驗(李建忠)—02
來源:互聯網
上載者:User
教程
第二講 C#語言基礎介紹
南京郵電學院 李建忠(cornyfield@263.net)
在體驗C#的銳利之前,關乎語言基本知識的掌握是必不可少的一環。由於C#基礎語言很多源自C/C++,在這裡對那些和C/C++類似的地方僅作簡單介紹,我們將體驗專註於那些區別於傳統C/C++的關鍵的語言基礎知識。
資料類型
C#語言的資料類型主要分為兩類:實值型別和參考型別。另外一種資料類型"指標"是為unsafe上下文編程專門設定的,其中unsafe上下文指對代碼進行unsafe標示以滿足利用指標對記憶體直接進行操作要求的C#Unmanaged 程式碼,這些代碼將失去Microsoft.NET平台的垃圾收集等CLR性質,我們放在"COM互操作 非託管編程與異常處理"專題裡闡述。實值型別的變數本身包含他們的資料,而參考型別的變數包含的是指向包含資料的記憶體塊的引用或者叫控制代碼。從下面這幅圖中可以清晰地看出兩者的差別:
參考型別帶來的可能的問題便是當多個變數引用同樣的記憶體塊時,對任何一個引用變數的修改都會導致該對象的值的改變。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;
l
布爾類型
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)來組織程式。命名空間可以嵌套。using指示符可以用來簡化命名空間類型的引用。using指示符有兩種用法。"using System;"語句可以使我們用簡短的類型名"Console"來代替類型"System.Console"。"using Output = System.Console;"語句可以使我們用別名"Output"來代替類型"System.Console"。命名空間的引入大大簡化了C#程式的組織方式。
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語句主要用於片斷資源管理。這些我們在後續章節裡都會有具體的涉及。