《.net編程先鋒C#》第四章 C#類型(轉)

來源:互聯網
上載者:User
編程 第四章 C#類型
既然你知道了怎樣建立一個簡單的C#程式,我將會給你介紹C#的類型系統。在這一章中,你學到如何使用不同的值和參考型別,加框和消框機制能為你作些什麼。儘管這一章的不側重於例子,但你可以學到很多重要的資訊,關於如何建立現成類型的程式。
4.1 實值型別
各種實值型別總是含有相應該類型的一個值。C#迫使你初始設定變數才能使用它們進行計算-變數沒有初始化不會出問題,因為當你企圖使用它們時,編譯器會告訴你。 每當把一個值賦給一個實值型別時,該值實際上被拷貝了。相比,對於參考型別,僅是引用被拷貝了,而實際的值仍然保留在相同的記憶體位置,但現在有兩個對象指向了它(引用它)。C#的實值型別可以歸類如下:
·簡單類型(Simple types )
·結構類型(struct types)
·枚舉類型(Enumeration types)
4.1.1 簡單類型
在C#中出現的簡單類型共用一些特性。第一,它們都是.NET系統類別型的別名。第二,由簡單類型組成的常量運算式僅在編譯時間而不是運行時受檢測。最後,簡單類型可以按字面被初始化。以下為C#簡單類型歸類:
·整型
·布爾型
· 字元型 (整型的一種特殊情況)
·浮點型
·小數型

4.1.1.1 整型
C#中有9個整型。 sbyte 、byte、 short、 ushort、 int、 uint、 long、 ulong 和 char(單獨一節討論)。它們具有以下特性:

·sbyte型為有符號8位整數,取值範圍在128~127之間。
·bytet型為無符號16位整數,取值範圍在0~255之間。
·short型為有符號16位整數,取值範圍在-32,768~32,767之間。
·ushort型為無符號16位整數,取值範圍在0~65,535之間。
·int型為有符號32位整數,取值範圍在-2,147,483,648~ 2,147,483,647之間。
·uint型為無符號32位整數,取值範圍在 0 ~ 4,294,967,295之間。
·long型為64位有符號整數,取值範圍在9,223,372,036,854,775,808~ 9,223,372,036,854,775,807之間。
·ulong型為64位不帶正負號的整數,取值範圍在0 ~ 18,446,744,073,709,551,615之間。

VB和C程式員都可能會對int和long資料類型所代表的新範圍感到驚訝。和其它的程式設計語言相比,在C#中,int不再取決於一個機器的字(word)的大小,而long被設成64位。

4.1.1.2 布爾型
布林值資料型別有true和false兩個布爾值。可以賦於true或false值給一個布爾變數,或可以賦於一個運算式,其所求出的值等於兩者之一:
bool bTest = (80 > 90);
與C和C++相比,在C#中,true值不再為任何非零值。不要為了增加方便而把其它整型轉換成布爾型。

4.1.1.3 字元型
字元型為一個單Unicode 字元。一個Unicode字元16位長,它可以用來表示世界上多種語言。可以按以下方法給一個字元變數賦值:
char chSomeChar = 'A';
除此之外,可以通過十六進位轉義符(首碼\x)或Unicode標記法給變數賦值(首碼\u):
char chSomeChar = '\x0065';
char chSomeChar = '\u0065';
不存在把char轉換成其它資料類型的隱式轉換。這就意味著,在C#中把一個字元變數當作另外的整數資料類型看待是行不通的——這是C程式員必須改變習慣的另一個方面。但是,可以運用顯式轉換:
char chSomeChar = (char)65;
int nSomeInt = (int)'A';
在C中仍然存在著轉義符(字元含義)。要換換腦筋,請看錶4.1。

Table 4.1 轉義符( Escape Sequences)

轉義符 字元名
\' 單引號
\" 雙引號
\\ 反斜線
\0 Null 字元
\a 驚嘆號(Alert )
\b 退格
\f 換頁
\n 新行
\r 斷行符號
\t 水平 tab
\v 垂直tab

4.1.1.4 浮點型
兩種資料類型被當作浮點型:float和double。它們的差別在於取值範圍和精度:
float: 取值範圍在 1.5x10^-45~ 3.4x10^38之間, 精度為7位元。
double: 取值範圍在 5.0x10^-324 ~ 1.7x10^308之間, 精度為 15~16 位元。
當用兩種浮點型執行運算時,可以產生以下的值:
正零和負零
正無窮和負無窮
非數字值(Not-a-Number,縮寫NaN)
非零值的有限數集
另一個運算規則為,當運算式中的一個值是浮點型時,所有其它的類型都要被轉換成浮點型才能執行運算。

4.1.1.5 小數型(The decimal Type)
小數型是一種高精度、128位元據類型,它打算用於金融和貨幣的計算。它所表示的範圍從大約1.0x10^-28 到 7.9x10^28,具有28至29位有效數字。要注意,精度是以位元 (digits)而不是以小數位(decimal places)表示。運算準確到28個小數位的最大值。
正如你所看到的,它的取值範圍比double的還窄,但它更精確。因此,沒有decimal和double之間的隱式轉換——往一個方向轉換可能會溢出,往另外一個方向可能會丟失精度。你不得不運用顯式轉換。
當定義一個變數並賦值給它時,使用 m 尾碼以表明它是一個小數型:
decimal decMyValue = 1.0m;
如果省略了m,在變數被賦值之前,它將被編譯器認作double型。

4.1.2 結構類型
一個結構類型可以聲明建構函式、常數、欄位、方法、屬性、索引、操作符和巢狀型別。儘管列出來的功能看起來象一個成熟的類,但在C#中,結構和類的區別在於結構是一個實值型別,而類是一個參考型別。與C++相比,這裡可以用結構關鍵字定義一個類。
使用結構的主要思想是用於建立小型的對象,如Point和FileInfo等等。你可以節省記憶體,因為沒有如類對象所需的那樣有額外的引用產生。例如,當聲明含有成千上萬個對象的數組時,這會引起極大的差異。
清單4.1 包含一個命名為IP的簡單結構,它表示一個使用byte類型的4個欄位的IP地址。我不包括方法等,因為這些工作正如使用類一樣,將在下一章有詳細的描述。

清單4.1 定義一個簡單的結構

1: using System;
2:
3: struct IP
4: {
5: public byte b1,b2,b3,b4;
6: }
7:
8: class Test
9: {
10: public static void Main()
11: {
12: IP myIP;
13: myIP.b1 = 192;
14: myIP.b2 = 168;
15: myIP.b3 = 1;
16: myIP.b4 = 101;
17: Console.Write("{0}.{1}.",myIP.b1,myIP.b2);
18: Console.Write("{0}.{1}",myIP.b3,myIP.b4);
19: }
20: }

4.1.3 枚舉類型
當你想聲明一個由一指定常量集合組成的獨特類型時,枚舉類型正是你要尋覓的。最簡單的形式,它看起來可能象這樣:
enum MonthNames { January, February, March, April };
因我慣用預設設定,故枚舉元素是int型,且第一個元素為0值。每一個連續的元素按1遞增。如果你想給第一個元素直接賦值,可以如下把它設成1:
enum MonthNames { January=1, February, March, April };
如果你想賦任意值給每個元素——甚至相同的值——這也沒有問題:
enum MonthNames { January=31, February=28, March=31, April=30 };
最後的選擇是不同於int的資料類型。可以在一條語句中按如此賦值:
enum MonthNames : byte { January=31, February=28, March=31, April=30 };
你可以使用的類型僅限於long、int、short和byte。


4.2 參考型別
和實值型別相比,參考型別不儲存它們所代表的實際資料,但它們儲存實際資料的引用。在C#中提供以下參考型別給你使用:
·物件類型
·類類 型
·介面
·代表元
·字串類型
·數組

4.2.1 物件類型
物件類型是所有類型之母——它是其它類型最根本的基類。因為它是所有對象的基類,所以可把任何類型的值賦給它。例如,一個整型:
object theObj = 123;
給所有的C++程式員一個警告:object並不等價於你可能正在尋找的void*。無論如何,忘掉指標總是個好主意。
當一個實值型別被加框(作為一個對象利用)時,物件類型就被使用了。這一章稍後會討論到加框和消框

4.2.2 類類型
一個類類型可以包含資料成員、函數成員和巢狀型別。資料成員是常量、欄位和事件。函數成員包括方法、屬性、索引、操作符、建構函式和解構函式。類和結構的功能是非常相似的,但正如前面所述,結構是實值型別而類是參考型別。
和C++相比,僅允許單繼承。(你不能擁有派生一個新對象的多重基類。) 但是,C#中的一個類可以派生自多重介面,該介面在下一節將得到描述。
第五章 “類”專門討論使用類編程。這一節僅打算給出C#類在哪裡適合類型圖的一個全貌。

4.2.3 介面
一個介面聲明一個只有抽象成員的參考型別。跟C++中相似的概念為:一個結構的成員,且方法等於0。如果你不知道那些概念的任何東西,這裡就是在C#中一個介面實際所做的。僅僅只存在著方法標誌,但根本就沒有執行代碼。這就暗示了不能執行個體化一個介面,只能執行個體化一個派生自該介面的對象。
可以在一個介面中定義方法、屬性和索引。所以,對比一個類,介面有什麼特殊性呢?當定義一個類時,可以派生自多重介面,而你只能可以從僅有的一個類派生。
你可能會問:"OK,但我必須實現所有的介面成員,那麼我能從這個途徑得到什麼呢?" 我想舉一個來自.NET的例子:很多類實現了IDictionary 介面。你可以使用簡單的類型轉換提供者:
IDictionary myDict = (IDictionary)someobjectthatsupportsit;
現在你的代碼可以訪問字典了。可等等,我說很多類可以實現這個介面——所以,你可以在多個地方重用代碼來訪問IDictionary 介面!一旦學會,任何地方都可使用。
當你決定在類設計中使用介面時,學習更多關於物件導向的設計是個好主意。這本書不能教你這些概念,但你可以學習如何建立介面。以下的程式碼片段定義介面IFace,它只有一個方法:
interface IFace
{
void ShowMyFace();
}
正如我所提到的,不能從這個定義執行個體化一個對象,但可以從它派生一個類。因此,該類必須實現ShowMyFace抽象方法:
class CFace:IFace
{
public void ShowMyFace()
{
Console.WriteLine("implementation");
}
}

介面成員和類成員的區別在於,介面成員不能被實現。因此,我不想在下一章中再次提到這一點。

4.2.4 代表元
一個代表元封裝了具有一些標誌的一個方法。基本上,代表元是型別安全和函數指標的安全版本(回調功能)。可以同時在一個代表元執行個體中同時封裝靜態和執行個體方法。
儘管你可以用代表員當作具有方法,但它們的主要用途是擁有有一個類事件。再次,我想把你引到下一章,那裡會詳細地討論類。
4.2.5 字串類型
C程式員可能會詫異,但當然,C#有一個用於操作字串資料的基底字元串類型。字串類直接派生自對象,且它是被密封的,這意味著再不能從它衍生類別。就象其它類型,字串是預定義類System String的一個別名。
它的用法十分簡單:
string myString = "some text";
合并字串同樣簡單:
string myString = "some text" + " and a bit more";
而如果你想訪問單個字元,所要做的就是訪問下標:
char chFirst = myString[0];
當比較兩個字串是否相等時,簡單地使用"=="比較操作符。
if (myString == yourString) ...
我只不過想提到,儘管字串是一個參考型別,比較時是比較值,而不是比較引用(記憶體位址)。
字串類型幾乎用於這本書的每一個例子中,而且在這些常式中,我會介紹給你一些由字串對象所顯露的極其有趣的方法。
4.2.6 數組
一個數組包含有通過計算下標訪問的變數。所有包含於數組中且被當作元素的變數必須是同一類型。這種類型自然被稱為"數群組類型"。數組可以儲存整數對象、字串對象或者 你提出的任何對象。
數組的維數就是所謂的排(rank),它決定了相關數組元素的下標數。最常用的數組是一維數組(第一排)。一個多維陣列具有的排數大於1 。每個維的下標始於0,終於維的長度減1 。
應有足夠的理論支援。讓我們看一下用一個數組初始化器( array initializer)初始化的數組:
string[] arrLanguages = { "C", "C++", "C#" };
該簡寫效果等同以下:
arrLanguages[0]="C"; arrLanguages[1]="C++"; arrLanguages[2]="C#";
而編譯器為你做了所有的工作。當然,它將同樣為多維陣列初始化器工作:
int[,] arr = {{0,1}, {2,3}, {4,5}};
它是以下的簡寫:
arr[0,0] = 0; arr[0,1] = 1;
arr[1,0] = 2; arr[1,1] = 3;
arr[2,0] = 4; arr[2,1] = 5;
如果你不想事先初始化一個數組,但知道了它的大小,該聲明就象這樣:
int[,] myArr = new int[5,3];
如果數組的大小必須動態地被計算,用於數組建立的語句可以象這樣寫:
int nVar = 5;
int[] arrToo = new int[nVar];
正如我在這一節開始所陳述的,你可以往數組裡面塞任何東西,只要所有的元素類型都相同。因此,如果你想把任何東西放進一個數組,就聲明它的類型為對象:

4.3 加框和消框
這一章的課程中,我已經給出了各式各樣的實值型別和參考型別。由於速度的原因,你會使用實值型別——它除了佔據一定空間的記憶體塊外,就沒有什麼了。但是,有時對象的方便性就象實值型別一樣好用。
這就是加框和消框登上了舞台的地方,加框和消框是C#類型系統的核心概念。通過允許一個實值型別轉換成類型對象或從類型對象轉換成實值型別,這種機制形成了實值型別和參考型別之間的捆綁串連。任何東西終究是一個對象——但是,僅當需要它們是對象時。
4.3.1 加框轉換
給一個值加框指隱式地把任何實值型別轉換成類型對象。當一個實值型別被加框時,一個對象執行個體就被分配,且實值型別的值被拷貝給新的對象。
看以下例子:
int nFunny = 2000;
object oFunny = nFunny;
第二行的賦值暗示調用一個加框操作。nFunny整型變數的值被拷貝給oFunny對象。現在整型變數和物件變數都同時存在於棧中,但對象的值居留在堆中。
那麼,它暗示著什麼呢?它們的值互相獨立——在它們之間沒有串連。(oFunny沒有引用nFunny的值。) 以下代碼說明了結果:
int nFunny = 2000;
object oFunny = nFunny;
oFunny = 2001;
Console.WriteLine("{0} {1}", nFunny, oFunny);
當代碼改變oFunny的值時,nFunny的值並沒有改變。只要你腦袋中有這個copy動作,就能夠使用實值型別的對象功能,發揮出你的巨大優勢!
4.3.2 消框轉換
和加框相比,消框是顯式操作——必須告訴編譯器,你想從對象中抽取出哪一種實值型別。當執行消框操作時,C#檢測所請求的實值型別實際上儲存在對象執行個體中。經過成功的校正,該值被消框。

這就是消框如何執行:
int nFunny = 2000;
object oFunny = nFunny;
int nNotSoFunny = (int)oFunny;

如果錯誤地請求一個double值
double nNotSoFunny = (double)oFunny;
通用語言運行時(Common Language Runtime,簡寫CLR)將會引發一個InvalidCastException異常。你可以在第7章 "異常處理" 中學到更多有關異常處理的知識。

4.4 小結
在這一章中,你學到了C#中用到的各種類型。簡單的實值型別包括整型、布爾型、浮點型和小數型。你會非常經常地用到一些類型,進行數學和金融的計算,還有邏輯表達。
在介紹參考型別之前,我顯示了一個看起來象類的結構類型。它幾乎如一個類般地運作,但它只是一個實值型別,這使它更加適合需要有大量的小對象的場合。
參考型別起始於所有對象之母的objedt本身。object是C#中所有對象的基類,且它同樣用於實值型別的加框和消框。除此之外,我還讓你領略了代表元、字串和數組。
令C#程式員十分神氣的類型就是類。它是C#物件導向編程的心臟,下一章整章專門讓你迅速理解這個激動人心且功能強大的類型。


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

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 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。