標籤:str 參考型別 轉換 code 執行個體化 回收 這一 bsp color
泛型什麼是泛型
泛型是 2.0 版 C# 語言和公用語言運行庫 (CLR) 中的一個新功能。泛型將型別參數的概念引入 .NET Framework,型別參數使得設計如下類和方法成為可能:這些類和方法將一個或多個類型的指定延遲到用戶端代碼聲明並執行個體化該類或方法的時候。例如,通過使用泛型型別參數 T,您可以編寫其他用戶端代碼能夠使用的單個類,而不致引入運行時強制轉換或裝箱操作的成本或風險
為什麼要使用泛型
我感覺泛型的最主要特點是減少了代碼的重用性,保護了型別安全,減少了拆裝箱的操作從而提高了效能
舉例說明
參考:http://www.blogjava.net/Jack2007/archive/2008/05/05/198566.html
我們在編寫程式時,經常遇到兩個模組的功能非常相似,只是一個是處理int資料,另一個是處理string資料,或者其他自訂的資料類型,但我們沒有辦法,只能分別寫多個方法處理每個資料類型,因為方法的參數類型不同。有沒有一種辦法,在方法中傳入通用的資料類型,這樣不就可以合并代碼了嗎?泛型的出現就是便可以輕鬆解決這個問題。
比如編寫一個處理int類型的棧
public class Stack { private int[] m_item; public int Pop(){...} public void Push(int item){...} public Stack(int i) { this.m_item = new int[i]; }}
上面代碼啟動並執行很好,但是,當我們需要一個棧來儲存string類型時,該怎麼辦呢?很多人都會想到把上面的代碼複製一份,把int改成string不就行了。當然,這樣做本身是沒有任何問題的,但一個優秀的程式是不會這樣做的,因為他想到若以後再需要long、Node類型的棧該怎樣做呢?還要再複製嗎?優秀的程式員會想到用一個通用的資料類型object來實現這個棧:
object 類型通用的棧
1 public class Stack 2 { 3 private object[] m_item; 4 public object Pop(){...} 5 public void Push(object item){...} 6 public Stack(int i) 7 { 8 this.m_item = new[i]; 9 }10 }
這個棧寫的不錯,他非常靈活,可以接收任何資料類型,可以說是一勞永逸。但全面地講,也不是沒有缺陷的,主要表現在:
當Stack處理實值型別時,會出現裝箱、折箱操作,這將在託管堆上分配和回收大量的變數,若資料量大,則效能損失非常嚴重。
在處理參考型別時,雖然沒有裝箱和折箱操作,但將用到資料類型的強制轉換操作,增加處理器的負擔。
在資料類型的強制轉換上還有更嚴重的問題(假設stack是Stack的一個執行個體):
1 Node1 x = new Node1();2 3 stack.Push(x);4 5 Node2 y = (Node2)stack.Pop();
上面的代碼在編譯時間是完全沒問題的,但由於Push了一個Node1類型的資料,但在Pop時卻要求轉換為Node2類型,這將出現程式運行時的類型轉換異常,但卻逃離了編譯器的檢查。
針對object類型棧的問題,我們引入泛型,他可以優雅地解決這些問題。泛型用用一個通過的資料類型T來代替object,在類執行個體化時指定T的類型,運行時(Runtime)自動編譯為本地代碼,運行效率和代碼品質都有很大提高,並且保證資料類型安全。
使用泛型實現這個棧
下面是用泛型來重寫上面的棧,用一個通用的資料類型T來作為一個預留位置,等待在執行個體化時用一個實際的類型來代替。讓我們來看看泛型的威力:
public class Stack<T> { private T[] m_item; public T Pop(){...} public void Push(T item){...} public Stack(int i) { this.m_item = new T[i]; }}
類的寫法不變,只是引入了通用資料類型T就可以適用於任何資料類型,並且型別安全的。這個類的調用方法:
//執行個體化只能儲存int類型的類
Stack<int> a = new Stack<int>(100);
a.Push(10);
a.Push("8888"); //這一行編譯不通過,因為類a只接收int類型的資料
int x = a.Pop();
//執行個體化只能儲存string類型的類
Stack<string> b = new Stack<string>(100);
b.Push(10); //這一行編譯不通過,因為類b只接收string類型的資料
b.Push("8888");
string y = b.Pop();
這個類和object實現的類有截然不同的區別:
1. 他是型別安全的。執行個體化了int類型的棧,就不能處理string類型的資料,其他資料類型也一樣。
2. 無需裝箱和折箱。這個類在執行個體化時,按照所傳入的資料類型產生本地代碼,本地代碼資料類型已確定,所以無需裝箱和折箱。
3. 無需類型轉換。
其它的用法,後期更新~~~~~
C# 泛型的簡單講解和應用