C#中的類型一共分為兩大類型:實值型別和參考型別。
實值型別包括:簡單類型,結構類型和枚舉類型,其中簡單類型又包括:整數類型,實數類型(double,float,decimal),布爾類型(bool),字元類型。這裡比較陌生的就是decimal,它表示小數,使用的時候必須在數字後面添加尾碼:M(float同理,添加F),否則會被當做double處理。
結構類型就是我們以前的結構體,定義的方式也是一樣的:
public struct Student{ public String name; public int number;};
訪問結構類型的成員像是這樣:Student.name。
結構類型可以有變數(但是不能初始化),也可以有方法,就像類一樣,但是不能被繼承。使用結構類型的原因就是它是實值型別,如果僅僅是一些資料的話,可以放在結構類型中,這樣開銷會比較小,但如果需要添加方法,就得使用類。
枚舉類型也是好用的類型,我們可以這樣定義一個枚舉:
enum City{ SHANGHAI, BEIJING};
因為枚舉已經變成了類型(事實上,java的枚舉也是一個類),所以我們可以進行類型轉換,像是這樣:
City city = City.SHANGHAI;int number = (int)city;City city2 = (City)number;
學過java的人都知道,枚舉中都是字面常量,我們可以像使用靜態欄位一樣直接使用。C#中的枚舉和java的枚舉使用方法都是一樣,但是,C#可以實作類別型轉換,這點倒是令我感到驚訝。
參考型別包括:字串類型,數群組類型,類類型,介面類型,委託類型和物件類型。
字串類型和其他語言是一樣的,先講講字串的比較,因為我們經常用到。
在java中,習慣使用equals(),不使用==的原因就是它預設是比較引用,但java不能重載運算子。C#中比較的原理是根據字串中每個字元的編碼值(C#使用Unicode編碼)。比較的方法很多,但我還是用回我習慣的Equals()好了。
C#中的字串還有一個非常好用的特性:對於字串需要進行轉義的字元,我們可以直接在該字串前面添加@字元,就不需要使用反斜線,像是這樣:
String s = @"c:\..";
以前的話,我們就得這樣使用:
String s = "c:\\..";
如果需要轉義的字元夠多,簡直就是惡夢!
字串類型還有一個問題:與其他類型的轉化。如果是java,我想把一個字串轉化為相應的int,我會使用Integer.parseInt(),在C#中,我們可以這樣使用:
int number = Int32.Parse("123");String str = Convert.ToString(number);
數群組類型作為參考型別並不奇怪,java中的數組除了儲存基本類型的數組之外,其他都是當做引用數組,但C#不存在基本類型的說法,它們所有的類型都是System.Object,即物件類型。
類類型和介面類型和java差不多,但介面類型不能包含欄位,所謂的欄位,其實就是初始化的變數,像是int i = 12是不允許的,而且,類的成員變數使用首碼_,而介面類型的變數首碼為I。
重點是委託類型。這是一個神奇的類型,它的作用類似設計模式中常說的委託類。
我們來看看一個簡單的委託類型的使用:
public delegate double PriceDelegate(); class Price { public double _Price; public void SetPrice(double price) { this._Price = price; } public double GetPrice() { return this._Price; } public double GetDiscountPrice() { return this._Price * 0.9; } }
接著我們來做一個測試:
public static void Main(String[] args){ Price price = new Price(); price.SetPrice(10); PriceDelegate delegatePrice = new PriceDelegate(price.GetPrice); Console.WriteLine(delegatePrice()); delegatePrice = new PriceDelegate(price.GetDiscountPrice); Console.WriteLine(delegatePrice()); }
我們可以看到,策略模式在這裡已經被內建了!我們可以利用委託類型簡單的實現策略模式(它到底算不算是策略模式還是個問題,因為策略模式是將演算法交給具體實現,但顯然我們一開始就已經在類中實現了,以後如果想要替換演算法,我們就必須到類的實現中修改,當然,使用繼承就可以解決這個問題,在衍生類別中添加新的演算法)。
更加嚴謹的說法應該是充分使用了回調,我們定義好一個方法,然後在需要的時候進行調用。委託類型是有局限的,它規定,作為參數的方法的傳回值和參數列表必須和委託類型一樣。基於這點,委託類型更接近函數指標,但顯然比它好用多了(學習C++的時候,指標的使用一直是我最大的痛苦!)。我們可以想象,在委託類型的運作中,調用作為參數的方法,然後將調用結果返回。委託類型讓我想到了javascript,這說明,C#比起java,物件導向的程度更高。
說到類型,繞不開的話題就是類型轉換,尤其是基本類型轉換為參考型別。
java中是利用封裝類實現基本類型的封裝,但是,C#是利用裝箱和拆箱機制。
C#中所有類型都可以向上轉型為System.Object,所以,我們將類型轉化為Object,這就是裝箱(很形象的說法,java是每個基本類型都有一個封裝類,就像每種糖果都有自己特有的封裝一樣,但是,C#直接利用一個Object將所有的東西裝起來,不就像一個箱子?),接著再強制轉換為我們需要的類型。
我們注意到,其實java的封裝機制和C#的裝箱機制完全不一樣,適用的範圍根本不一樣,封裝機制是將基本類型轉化為對應的封裝類,裝箱機制是將所有實值型別轉化為Object。
講到類型轉換,C#總是讓我大開眼界,像是專門用於轉型的is和as操作符,就讓我會心一笑。
我們可以使用is操作符來檢查一個對象是否相容於指定的類型,並返回一個Boolean值。
public static void Main(String[] args) { Object obj = new Object(); Boolean boolean = (obj is Object); Console.WriteLine(boolean); }
is操作符永遠不會拋出異常,這是值得注意的。我們經常像是這樣使用is操作符:
public static void Main(String[] args) { int number = 5; float f = 6.0F; Show(number); Show(f); } public static void Show(Object number) { if (number is int) { Console.WriteLine(number); } else { Console.WriteLine("請重新輸入一個整數"); } }
嗯,java的instanceof關鍵字跑到我腦海中了,如果沒有學過java,請無視這句。
as操作符用於簡化類型轉換:
public static void Main(String[] args) { Object obj = new Object(); People people = obj as People; Show(people); } public static void Show(Object obj) { if (obj is People) { Console.WriteLine(obj); } else { Console.WriteLine("請給我一個人"); } } class People { private String _Name = "人"; public override String ToString() { return _Name; } }
as操作更多是簡化我們上面的is操作:
public static void Show(Object obj) { People people = obj as People; if (people != null) { Console.WriteLine(people); } else { Console.WriteLine("請給我一個人"); } }
如果as操作符進行轉換時,發現類型不符,並不會報錯而是返回一個null。
C#中有很多神奇的東西,值得我們繼續研究下去。