泛型【詳解】

泛型 
一、什麼是泛型? 
通過泛型可以定義類型安全類,而不會損害類型安全、性能或工作效率 

二、實例化泛型 
1、可以使用任何類型來聲明和實例化 
2、申明和實例話都必須用一個特定的類型來代替一般類型T 
3、例子: 
//原來寫法 
Public   class   Stack 

object[]   m_Items; 
public   void   Push(object   item) 
{...} 
public   object   Pop() 
{...} 

Stack   stack   =   new   Stack(); 
stack.Push(1); 
int   number   =   (int)stack.Pop(); 

//有了泛型後 
Public   class   Stack <T> 

T[]   m_Items; 
public   void   Push(T   item) 
{...} 
public   T   Pop() 
{...} 

Stack <int>   stack   =   new   Stack <int> (); 
stack.Push(1); 
int   number   =   (int)stack.Pop(); 

三:泛型的好處 
1、一次性的開發、測試和部署代碼,通過任何類型來重用它 
2、編譯器支持和類型安全 
3、不會強行對值類型進行裝箱和取消裝箱,或者對引用類型進行向下強制類型轉換,所以性能得到顯著提高。 
注:值類型大概可以提高200%,引用類型大概爲100% 

四:多個泛型 
1、單個類型可以定義多個泛型 

五:泛型別名 
1、在文件頭部使用using   爲特定類型取別名,別名作用範圍是整個文件 
2、例子 
using   List   =   LinkedList <int,string> ; 
class   ListClient 

static   void   Main(string[]   args) 

List   list   =   new   List(); 
list.AddHead(123, "AAA "); 



五:泛型約束 
(1)、派生約束 
如: 
public   class   LinkedList <K,T>   where   K:IComparable 

T   Find(K   key) 

if   (str.Key.CompareTo(key)   ==   0)//只有實現這個接口才可比較 



注意: 
1、所有的派生約束必須放在類的實際派生列表之後 
如:public   class   LinkedList <K,T> :IEnumerable <T>   where   K:IComparable <K> 
        {...} 
2、一個泛型參數上可以約束多個接口(用逗號分隔) 
public   class   LinkedList <K,T>   where   K:IComparable <K> ,IConvertible 
3、在一個約束中最多隻能使用一個基類 
4、約束的基類不能是密封類或靜態類 
5、不能將System.Delegate或System.Array約束爲基類 
6、可以同時約束一個基類以及一個或多個接口,但是該基類必須首先出現在派生約束列表中。 
7、C#允許你將另一個泛型參數指定爲約束 
public   class   MyClass <T,U>   where   T:U 
{...} 
8、可以自己定義基類或接口進行泛型約束 
9、自定義的接口或基類必須與泛型具有一致的可見性 

(2)、構造函數約束 
如: 
class   Node   <K,T>   where   T:new() 


注意: 
1、可以將構造函數的約束和派生約束結合起來,前提是構造函數的約束出現在約束列表中的最後 

(3)、引用/值類型約束 
1、可以使用struct約束將泛型參數約束爲值類型(如int、bool、enum),或任何自定義結構 
2、同樣可以使用class約束將泛型參數約束爲引用類型 
3、不能將引用/值類型約束與基類約束一起使用,因爲基類約束涉及到類 
4、不能使用結構和默認構造函數約束,因爲默認構造函數約束也涉及到類 
5、雖然您可以使用類和默認構造函數約束,但是這樣做沒有任何價值 
6、可以將引用/值類型約束與接口約束組合起來,前提是引用/值類型約束出現在約束列表的開頭 

六:泛型和強制類型轉換 
1、C#編譯器只允許將泛型參數隱式轉換到Object或約束指定的類型 
如: 
interface   IS{...} 
class   BaseClass{...} 
class   MyClass <T>   where   T:BaseClass,IS 

void   SomeMethod(T   t) 

IS   obj1   =   t; 
BaseClass   obj2   =   t; 
object   obj3   =   t; 


2、編譯器允許你將泛型參數顯示強制轉換到其他任何藉口,但不能將其轉換到類 
interface   IS{...} 
class   SomeClass{...} 
class   MyClass   <T>   //沒有約束 

void   SomeMethod(T   t) 

IS   obj1   =   (IS)t;   //可以 
SomeClass   obj2   =   (SomeClass)t   //不可以 


3、可以使用臨時的Object變量,將泛型參數強制轉換到其他任何類型 
class   SomeClass{...} 
class   MyClass   <T>   

void   SomeMethod(T   t) 

object   temp   =   t; 
SomeClass   obj   =   (SomeClass)temp;//可以 


注意:這裏只是告訴你這樣寫是可以的,但是要不要這樣寫?不要這樣寫,因爲如果t確實沒有繼承SomeClass編譯沒錯但是運行就會出錯 
4、解決上面強制轉換問題,可以使用is和as運算符進行判斷 
public   class   MyClass <T> 

public   void   SomeMethod <T   t> 

if   (t   is   int   ){...} 
if   (t   is   LinkedList <int,string> ){...} 
//如果泛型參數的類型是所查詢的類型,則is運算符返回true 
string   str   =   t   as   string; 
//如果這寫類型兼容,則as將執行強制類型轉換,否則將返回null 
if   (str   !=   null){...} 
LinkedList <int,string>   list   =   t   as   LinkedList <int,string> ;
if   (list   !=   null){...} 



七:繼承和泛型 
1、在從泛型基類派生,可以提供類型實參,而不是基類泛型參數 
public   class   BaseClass <T> {...} 
public   class   SubClass:BaseClass <int> 
2、如果子類是泛型,而非具體的類型實參,則可以使用子類泛型參數作爲泛型基類的指定類型 
public   class   BaseClass <TT> {...} 
public   class   SubClass <T> :BaseClass <T> {...} 
3、在使用子類泛型參數時,必須在子類級別重複在基類級別規定的任何約束 
4、基類可以定義其簽名使用泛型參數的虛禮方法,在重寫它們時,子類必須在方法簽名中提供相應的類型。 
如: 
public   class   BaseClass <T> 

public   virtual   T   SomeMethod() 
{...} 

public   class   SubClass:BaseClass <int> 

public   override   int   SomeMethod() 
{...} 

5、如果該子類是泛型,則它還可以在重寫時使用它自己的泛型參數 
public   class   SubClass <T> :BaseClass <T> 

public   override   T   SomeMethod() 
{...} 

6、你可以定義泛型接口、泛型抽象類,甚至泛型抽象方法。 
7、不能對泛型參數使用+或+=之類的運算符 
public   class   Calculator <T> 

public   T   Add   (T   arg1,T   arg2) 

return   arg1   +   arg2;//錯誤 


但是我們可以通過泛型抽象類、接口來實現在個功能,因爲實現泛型抽象類、接口我們就已經明確傳一個參數了,就可以執行諸如+這樣的操作。 

八:泛型方法 
1、方法可以定義特定於其執行範圍的泛型參數 
public   class   MyClass <T> 

public   void   MyMethod <X> (X   x) 
{...} 

2、即使各包含類根本不使用泛型,你也可以定義方法特定的泛型參數 
public   class   MyClass 

public   void   MyMethod <T> (T   t) 
{...} 

注意:該功能只使用於方法,屬性,索引器只能使用在類的作用範圍中定義的泛型參數。 
3、調用泛型方法 
MyClass   obj   =   new   MyClass(); 
obj.MyMethod <int> (3); 
也可以這樣: 
MyClass   obj   =   new   MyClass(); 
obj.MyMethod(3);   //該功能稱爲泛型推理 
4、泛型方法也可以有自己的泛型參數約束 
pubic   class   MyClass 

public   void   SomeMethod <T> (T   t)   where   T:IComparable <T> 
{...} 

5、子類方法實現不能重複在父級別出現的約束 
public   class   BaseClass 

public   virtual   void   SomeMethod <T> (T   t)where   T:new() 
{...} 

pubic   class   SubClass:BaseClass 

public   override   void   SomeMethod <T> (T   t)//不能再有約束 
{...} 

6、靜態方法 
靜態方法可以定義特定的泛型參數和約束 
public   class   MyClass <T> 

public   static   T   SomeMethod <X> (T   t,X   x) 
{...} 

int   number   =   MyClass <int> .SomeMethod <string> (3, "AAA "); 
或者:int   mumber   =   MyClass <int> .SomeMethod(3, "AAA "); 

九:泛型委託 
1、在某個類中定義的委託可以利用該類的泛型參數 
2、委託也可以定義自己的泛型參數
發佈了96 篇原創文章 · 獲贊 2 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章