程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 8、泛型,泛型

8、泛型,泛型

編輯:C#入門知識

8、泛型,泛型


首先陳述,這是一篇水文,因為文字內容比較干,主要是一些介紹和概念。但對泛型理解還是有一定的幫助。沒有過多的代碼解釋,勿怪。

引入:.net2.0發布之後,C#編程語言開始支持泛型,用以增強它的特性,基於此,在基礎類庫中引入了一個以集合為中心的新命名空間:System.Collections.Generic命名空間。 

第一個問題:為什麼要引入泛型。其實也就是和數組之間的區別之處。

1、之前提到過C#的數組,數組這種數據結構可以提供一組固定上限的同一類型項。但有很多時候,我們卻需要更靈活的數據結構,例如,可以增長和收縮的容器。以及容器可以保存符合某個條件的對象。 2、類型安全和性能優勢。(約束)   既然如此,那麼就先從非泛型集合開始看起,逐漸過渡。  

一、非泛型集合

我們知道,我們經常用mscorlib.dll中的System.Collections命名空間中很多類來組織數據。例如,ArrayList、Hashtable、Queue、Stack、SortedList。 使用這些類將會導致許多問題。 1、低性能。特別在操作數據結構的時候(值類型)。當我們在經典的集合類中存儲結構時,CLR必須執行大量的內存轉換。 2、有些經典的集合類不是類型安全的,因為他們是為了操作System.Object類而開發的。因此,可以包含任何類型。   強調:任何使用.net2.0或者更高版本創建的項目都應該放棄使用System.Collections中的類,而使用System.Collections.Generic中的類。 

第一個問題,性能

之前提到,.net支持兩大數據類型:值類型和引用類型。有時候我們需要使用一個類別的變量表示另一個類別的變量,於是C#提供了成為裝箱的簡單機制。這允許我們將值類型保存在引用類型變量中。 裝箱:顯示的將值類型分配給System.Object變量的過程。這個過程,CLR會在堆上分配新的對象並將值類型的值復制到那個實例上,返回給我們的是新分配在堆上對象的引用。 拆箱:與裝箱相反,把保存在對象引用中的值轉換回棧上的相應值類型。(更像是類型轉換操作,但語義上卻迥然不同,因為拆箱CLR會驗收值類型是不是等價於裝箱的類型,如果是則將值類型復制回本地棧變量上。)所以與轉換不同,拆箱必須回到合適的數據類型。 注意:Console.WriteLine()方法操作的對象也是Object類型,故而當輸出的時候,我們的值會被再次裝箱。 裝箱拆箱發生的步驟如下: 1.必須在托管堆上分配一個新對象。 2。基於棧數據的值必須被轉移到新分配的內存位置。 3.在拆箱時,保存在堆上的對象中的值必須轉移回棧。 4.堆上無用的對象(最後)會被回收。   由此可見,當我們操作大數據量的時候,建會產生大量的裝箱拆箱操作,性能就是一個很大的問題了。理想情況下,我們應該可以在沒有任何性能問題的容器中操作站數據,並且在獲取數據的時候也不必使用try、catch作用域。(這正是泛型所實現的。) 

第二個問題,類型安全

前面提到,在System.Collections命名空間下大多數類所操作的都是Object類型,因此他們可以容納任何類型,這就導致了類型安全問題。 而我們大多數情況下,需要一個類型安全的容器來操作特定的數據類型。而為了做到這些,我們需要自定義類型集合。 然而,自定義集合,卻並沒有消除裝箱拆箱的損失,例如不管用哪種類型來保存整數,我們都不可避免的使用非泛型容器帶來的裝箱問題。   這就需要使用泛型,泛型可以消除上述帶來的損耗和安全問題。與非泛型相比,泛型的優勢如下: 1、更好的性能,不會導致裝箱拆箱損耗。 2、類型安全,他們只包含指定類型。 3、大幅度減少了構建自定義類型集合的需要,因為基礎類庫提供了幾個預制的容器。 

二、泛型類型參數的作用。

例如:List<T> 尖括號中的標記的正式名稱為類型參數,通俗的可以將其稱為占位符。<T>讀作of T。 在創建泛型對象、實現泛型接口或調用泛型成員時,為泛型參數提供的值是由開發者決定的。 1、當我們為泛型類或結構指定特定的類型參數時候,例如Person類的泛型集合,List<Person>。當創建List<T>變量的時候,編譯器並沒有為List<T>創建全新的實現,而只處理你實際調用的泛型類型的成員。 2、除了可以給泛型類指定類型成員,還可以死給泛型成員指定類型成員(即方法和屬性。)。例如List<int> intList;還有泛型接口,interface IComparable<T> 

三、System.Collections.Generic命名空間

之前我們學習過對象初始化語法,現在我們看一下集合初始化語法: 這種語法特性,讓你可以用與填充基礎數組類似的語法,來填充ArrayList或List<Y>等容器。 說明,只能支持Add()方法的類使用集合初始化語法,這是ICollection<T>或ICollection接口決定的。 如建立一個point集合類,可以如下表示: List<Point> mylit = new List<Point> {     new point{x=1,y=1},     new point{x=2,y=2},     ... }; 這種語法的好處是減少鍵盤輸入,但是壞處則是影響可讀性。   此命名空間下,包括幾種泛型類。 List<T>,使用最廣,用以動態調整的類型。 Stack<T>,棧,後進先出的數據集合,包含push和pop方法,分別比歐式進棧和出棧。 Queue<T>,隊列,先進先出的數據集合,包括Dequeue和Enqueue方法,分別表示在移除開始處對象(並返回)和在隊列末尾添加一個對象,除此之外,還有Peek方法,返回隊列開始處對象,但並不移除。 SortedSet<T>,這個類中的項是自動排序的,在插入和移除之後,也能自動排序,因此該類十分有用。 

四、創建自定義的泛型方法/泛型結構和類。

傳統方法,交換兩個整數: Swap(ref int a, ref int  b){ int temp; temp = a; a = b; b = temp;} 如果我們繼續要交換兩個Person對象,則我們必須編寫一個swap的新版本: Swap(ref Person a, ref Person b){ Person temp; temp = a; a = b; b = temp;} 如果需要交換其他的數據,則需要定義更多的方法,這就會給維護帶來麻煩,如果想要有單一的方法,我們需要創建操作Object類型的方法,但這樣會導致裝箱、拆箱,類型安全,顯示轉換等問題。 如果你要創建的方法重載只是輸入參數不同,可以使用泛型。方法如下: Swap<T>(ref T a, ref T b){T temp; temp = a; a = b; b = temp;}   我們還可以創建泛型類或結構:public class Point<T>{} 其中,我們可以是一個雙精度的point也可以是一個int的point。 1、default(T),和泛型一塊兒使用的時候,它表示一個類型參數的默認值。這非常有用,因為一個泛型類型預先並不知道實際的真為輔,因此無法安全的假設默認值是什麼。默認值如下: 數值的默認值為0;引用類型的默認值是null;一個結構的字段被設為0(值類型)或null(引用類型)。 2、泛型基類,泛型類可以作為其他類的基類,它可以定義許多虛方法和抽象方法。但是要做到這些,泛型類需要遵循一些守則: 首先,如果一個非泛型類型擴展了一個泛型類,派生類必須指定一個類型參數。public class B:A<string>{}.其中A類為我們自定義的泛型類。 其次,如果泛型基類定義了泛型虛方法或抽象方法,派生類型必須使用指定類型參數重寫泛型方法。 最後,如果派生類型也是泛型,則它能夠(可選的)重用類型占位符。不過要注意派生類必須遵照基類中的任何約束。 

五,類型參數的約束

如本節描述,任何泛型都必須至少有一個類型參數,並在與泛型類型或參數交互時指定該類型參數,這可以使我們構建類型安全的代碼。 .net平台使用where關鍵字可以得到更加具體的類型參數信息。下面幾種約束表示如下: where T:struct,該類型參數<T>必須在其繼承鏈中包含System.ValueType值類型,即必須為結構。 where T : class,和上面相反,不能包含值類型,必須為引用類型。 where T : new(),該類型參數<T>必須包含一個默認的構造函數,因為無法預知子定義構造函數格式,所以如果泛型類型必須創建一個類型參數的實例,這將是非常有用的。注意,在有多個約束的時候,此約束必須列在末尾。 where T : NameOfBaseClass,該類型參數<T>必須派生於NameOfBaseClass指定的類。 where T : NameOfInterface,同上,必須派生於指定接口,多個接口必須用逗號隔開。 例如,如果要指定泛型智能操作結構,可以這樣: Swap<T>(ref T a, ref T b) where T : struct {....}。以這種方式約束了Swap方法就不能再對其他如string對象進行交換了,因為string是引用類型。 

六,小結

本小節主要陳述了泛型對比之前的經典容器有的一些優勢。類型安全、高效、減少代碼量。除此之外,還知道了泛型約束的一些知識。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved