1. 程式人生 > >C# 泛型的簡單講解和應用

C# 泛型的簡單講解和應用

出現 ava 問題 this bsp div arc 但是 int

泛型

什麽是泛型

  泛型是 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# 泛型的簡單講解和應用