.NET 泛型

 

  • 泛型
     泛型將類型參數的概念引入 .NET Framework,類型參數使得設計以下類和方法成爲可能:這些類和方法將一個或多個類型的指定推遲到客戶端代碼聲明並實例化該類或方法的時候。例如,經過使用泛型類型參數 T,您能夠編寫其餘客戶端代碼可以使用的單個類,而不致引入運行時強制轉換或裝箱操做的成本或風險。
     使用泛型類型能夠最大限度地重用代碼、保護類型的安全以及提升性能。泛型最多見的用途是建立集合類。能夠建立本身的泛型接口、泛型類、泛型方法、泛型事件和泛型委託。能夠對泛型類進行約束以訪問特定數據類型的方法。關於泛型數據類型中使用的類型的信息可在運行時經過反射獲取。
 
public class GenericList<T>
{
    void Add(T input) { }
}
class TestGenericList
{
    private class ExampleClass { }
    static void Main()
    {
        GenericList<int> list1 = new GenericList<int>();
        GenericList<string> list2 = new GenericList<string>();
        GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
    }
}
  • 泛型類型參數
    • 爲泛型類、結構指定類型參數
    • 爲泛型成員指定類型參數
    • 爲泛型接口指定類型參數
  • 泛型默認值類型
    • 關鍵字:default
  • 非泛型集合
     System.Collections中大量的定義了非泛型集合類和接口
  • 經常使用類
    • ArrayList
    • Hashtable
    • Queue
    • SortedList
    • Stack
  • 經常使用接口
    • ICollection
    • ICloneable
    • IDictionary
    • IEnumerable
    • IEnumerator
    • IList
  • 性能問題
     使用非泛型集合時全部的數據都是被存放爲object對象,因此在使用非泛型集合時存在裝箱拆箱的過程,這是一個相似於數據轉換的過程,若是存放的數據是值類型的還會涉及大量的內存堆棧轉換操做,所以性能影響比較大。
  • 類型安全問題
     也是由於非泛型集合存放數據使用的是object對象,因此在拆箱的過程當中若是接收變量的類型與原類型不兼容則不會出現異常
 
  • 自定義泛型方法
     泛型方法是使用類型參數聲明的方法,泛型方法是一個增強版的方法重載方式,該方法最大的優點在於,只要維護一個方法的版本,並且它能以類型安全的方式操做任意給定參數類型的項,更爲重要的是棧數據保留在棧上,堆數據保留在堆上。
 
static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}
  • 自定義泛型類與結構
     泛型類封裝不是特定於具體數據類型的操做。泛型類最經常使用於集合,如連接列表、哈希表、堆棧、隊列、樹等,其中,像從集合中添加和移除項這樣的操做都以大致上相同的方式執行,與所存儲數據的類型無關。
 
class BaseNode { }
class BaseNodeGeneric<T> { }
class NodeConcrete<T> : BaseNode { }
class NodeClosed<T> : BaseNodeGeneric<int> { }
class NodeOpen<T> : BaseNodeGeneric<T> { }
  • 泛型基類
     泛型類能夠做爲其餘類的基類。
    • 派生規則
      • 若是非泛型類擴展泛型類,派生類必須指定一個類型參數。
      • 若是泛型基類定義了泛型虛方法和抽象方法,派生類必須使用指定類型參數重寫泛型方法。
      • 若是派生類也是泛型,則它可以重用類型佔位符,不過派生類必須遵守基類中的任何約束。
  • 類型參數的約束
     在定義泛型類時,能夠對客戶端代碼可以在實例化類時用於類型參數的類型種類施加限制。若是客戶端代碼嘗試使用某個約束所不容許的類型來實例化類,則會產生編譯時錯誤。這些限制稱爲約束。約束是使用 where 上下文關鍵字指定的。
     若是要檢查泛型列表中的某個項以肯定它是否有效,或者將它與其餘某個項進行比較,則編譯器必須在必定程度上保證它須要調用的運算符或方法將受到客戶端代碼可能指定的任何類型參數的支持。這種保證是經過對泛型類定義應用一個或多個約束得到的。例如,基類約束告訴編譯器:僅此類型的對象或今後類型派生的對象纔可用做類型參數。一旦編譯器有了這個保證,它就可以容許在泛型類中調用該類型的方法。約束是使用上下文關鍵字 where 應用的。
 
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new() {}
  • 類型參數約束表
約束 說明

T:結構web

類型參數必須是值類型。能夠指定除 Nullable 之外的任何值類型。有關更多信息,請參見使用可空類型(C# 編程指南)編程

T:類數組

類型參數必須是引用類型,包括任何類、接口、委託或數組類型。安全

T:new()函數

類型參數必須具備無參數的公共構造函數。當與其餘約束一塊兒使用時,new() 約束必須最後指定。性能

T:<基類名>spa

類型參數必須是指定的基類或派生自指定的基類。設計

T:<接口名稱>orm

類型參數必須是指定的接口或實現指定的接口。能夠指定多個接口約束。約束接口也能夠是泛型的。對象

T:U

爲 T 提供的類型參數必須是爲 U 提供的參數或派生自爲 U 提供的參數。這稱爲裸類型約束。

  • 未綁定的類型參數
     沒有約束的類型參數(如公共類 SampleClass<T>{} 中的 T)稱爲未綁定的類型參數。未綁定的類型參數具備如下規則:
    • 不能使用 != 和 == 運算符,由於沒法保證具體類型參數能支持這些運算符。
    • 能夠在它們與 System.Object 之間來回轉換,或將它們顯式轉換爲任何接口類型。
    • 能夠將它們與 null 進行比較。將未綁定的參數與 null 進行比較時,若是類型參數爲值類型,則該比較將始終返回 false。
  • 裸類型約束
     用做約束的泛型類型參數稱爲裸類型約束。當具備本身的類型參數的成員函數須要將該參數約束爲包含類型的類型參數時,裸類型約束頗有用。
 
class List<T>
{
    void Add<U>(List<U> items) where U : T {}
}
     
     在上面的示例中,T 在 Add 方法的上下文中是一個裸類型約束,而在 List 類的上下文中是一個未綁定的類型參數。
     裸類型約束還能夠在泛型類定義中使用。注意,還必須已經和其餘任何類型參數一塊兒在尖括號中聲明瞭裸類型約束:
 
public class SampleClass<T, U, V> where T : V { }
 
     泛型類的裸類型約束的做用很是有限,由於編譯器除了假設某個裸類型約束派生自 System.Object 之外,不會作其餘任何假設。在但願強制兩個類型參數之間的繼承關係的狀況下,可對泛型類使用裸類型約束。
相關文章
相關標籤/搜索