在C# 2.0中引入了泛型,泛型的出現解決了編碼中的很多問題。相信大家一定經常用到"System.Collections.Generic"命名空間中的泛型集合類("Generic"就是泛型的意思)。在C# 1.0中,我們還在使用"System.Collections"命名空間中的非泛型集合類,那麼看看我們在沒有泛型的時候遇到的問題。
問題1:強制類型轉換
ArrayList stuList = new ArrayList(); Student wilber = new Student { Name = "Wilber", Age = 27, Gender = "Male" }; stuList.Add(wilber); Student stu = (Student)stuList[0]; stuList.Add(10);
在使用非泛型集合ArrayList時,所有的對象都是以object類型加入ArrayList,當對象從ArrayList取出的時候也是object類型,這時我們就需要進行強制類型轉換,如果轉換不當,就會得到一個運行時的錯誤;即使我們向ArrayList添加不同類型的對象時,也不會報錯(例如上面向stuList中加入了一個int值)。
問題2:裝箱和拆箱
在上面的例子中,如果我們使用ArrayList存放一組值類型的數據(例如一組int值),存入時,每個值類型的數據都要進行裝箱為object類型;取出時,每個object類型的數據又要進行拆箱操作。
可以看到,在使用非泛型集合的時候,用戶需要自己進行類型轉換,並且可能遇到運行時的類型轉換異常;同時,對於值類型的操作 ,非泛型集合會有裝箱和拆箱帶來的效率問題。
對於上面的問題,我們可以使用C# 2.0中的泛型集合。
這樣一來,我們就通過類型參數(例子中的Student)來限制List可以包含的實例類型,從而避免的強制類型轉換。
同時,通過類型參數,編譯器可以進行類型檢查,當試圖往List中存入一個與類型參數不匹配的對象的時候,編譯器就是給出錯誤提示。
List<Student> stuList = new List<Student>(); Student wilber = new Student { Name = "Wilber", Age = 27, Gender = "Male" }; stuList.Add(wilber); Student stu = stuList[0]; stuList.Add(10);
下面我們看看泛型中的一些概念和術語。
泛型有兩種表現形式:泛型類型(包括類、接口、委托和結構,沒有泛型枚舉)和泛型方法。在泛型類型和泛型方法中都會有類型參數,當通過泛型類型實例化對象或者對泛型方法調用的時候,都需要使用一個真實的類型來代替類型參數。
類型參數是真實類型的占位符,在泛型聲明過程中,所有的類型參數放在一對間括號中(<>),通過逗號分隔。
根據類型參數不同的指定類型實參的情況,泛型類型可以分為:
類型是對象的藍圖,我們可以通過類型來實例化對象;那麼對於泛型來說,未綁定泛型類型是以構造泛型類型的藍圖,已構造泛型類型又是實際對象的藍圖。
下圖就是一個簡單的例子,Dictionary<TKey, TValue>就是一個泛型類型(未綁定泛型類型,開放類型);通過制定類型參數,可以得到不同的封閉類型;通過不同的封閉類型有可以構造不同的實例。
我們都已經習慣了方法的參數和返回值擁有固定的類型,這裡就看看“參數化”的方法。對於泛型方法,可以理解為擁有類型參數的方法。
對於上面例子中Dictionary<TKey, TValue>這個泛型類型,有很多方法可以使用,例如:
注意,這些方法中沒有一個是真正的泛型方法,他們只是使用了泛型類型的類型參數。
真正的泛型方法應該擁有自己的類型參數,當我們使用泛型方法的時候,要給泛型方法的類新參數指定類型實參,接下來看一個泛型方法的例子。
class Program { static void Main(string[] args) { Console.WriteLine("The bigger one is {0}", GetBiggerOne<int>(3,9)); Console.WriteLine("The bigger one is {0}", GetBiggerOne<string>("Hello", "World")); Console.Read(); } public static T GetBiggerOne<T>(T itemOne, T itemTwo) where T : IComparable { if (itemOne.CompareTo(itemTwo) > 0) { return itemOne; } return itemTwo; } }
在上面的例子中,我們使用泛型方法來實現一個兩個元素比較的例子,我們看到方法"GetBiggerOne"擁有自己的類型參數,當我們看到一個泛型方法時,可以一步步用真實的類型替換泛型方法中的類型參數,這樣就會簡化我們的分析。
對於泛型的類型約束,將在下面一篇文章介紹。
根據上面的分析,可以看到泛型有一些的優點:
泛型的出現,給我們帶來了很多好處,泛型實現了類型和方法的"參數化"。
基於泛型,我們可以實現代碼重用,並且泛型為我們提供了類型安全檢查。對於值類型的操作,通過泛型可以避免裝箱和拆箱帶來的性能損失。
同樣C# 2.0 以後,就建議只在代碼中使用支持泛型的集合類了(System.Collections.Generic)。