理解C#泛型

來源:互聯網
上載者:User

標籤:

在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);

 

泛型中的術語

下面我們看看泛型中的一些概念和術語。

泛型有兩種表現形式:泛型型別(包括類、介面、委託和結構,沒有泛型枚舉)和泛型方法。在泛型型別和泛型方法中都會有型別參數,當通過泛型型別執行個體化對象或者對泛型方法調用的時候,都需要使用一個真實的類型來代替型別參數。

型別參數是真實類型的預留位置,在泛型聲明過程中,所有的型別參數放在一對間括弧中(<>),通過逗號分隔。

泛型型別

根據型別參數不同的指定類型實參的情況,泛型型別可以分為:

  • 如果沒有為型別參數提供類型實參,那麼聲明的就是一個未綁定泛型型別(unbound generic)
  • 如果指定了類型實參,該類型就稱為已構造類型(constructed type),然而已構造類型又可以是開放類型或封閉類型的
    • 包含型別參數的類型就是開放類型(open type)(所有的未綁定的泛型型別都屬於開放類型的),
    • 每個型別參數都指定了類型實參就是封閉類型(closed type)

類型是對象的藍圖,我們可以通過類型來執行個體化對象;那麼對於泛型來說,未綁定泛型型別是以建構的泛型型別的藍圖,已建構的泛型型別又是實際對象的藍圖。

就是一個簡單的例子,Dictionary<TKey, TValue>就是一個泛型型別(未綁定泛型型別,開放類型);通過制定型別參數,可以得到不同的封閉類型;通過不同的封閉類型有可以構造不同的執行個體。

泛型方法

我們都已經習慣了方法的參數和傳回值擁有固定的類型,這裡就看看“參數化”的方法。對於泛型方法,可以理解為擁有型別參數的方法。

對於上面例子中Dictionary<TKey, TValue>這個泛型型別,有很多方法可以使用,例如:

  • void Add(TKey, key, TValue value)
  • bool ContainsValue(TValue value)
  • bool ContainsKey(TKey key)

注意,這些方法中沒有一個是真正的泛型方法,他們只是使用了泛型型別的型別參數

真正的泛型方法應該擁有自己的型別參數,當我們使用泛型方法的時候,要給泛型方法的類新參數指定類型實參,接下來看一個泛型方法的例子。

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)。

 

理解C#泛型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.