一次編碼多次使用這就是引入泛型的根源在以前的C++中稱為模板C#泛型通過算法和數據結構支持獨立編碼例如泛型列表意味著你不必再重寫一個強類型集合在本文中作者將向你展示定義和使用泛型是多麼容易的事情請注意長期以來泛型一直被認為是最高級和最困難的術語
一 簡介
泛型現在在任何一種語言中都被認為是一個高級的強有力的術語當我在C++中第一次接觸模板時我對之有些疑惑之後我讀了Bjarne Stroustrop的《The Design and Evolution of C++》才發現模板的使用就象C中的宏和用之來取代的簡單串替換模板一樣容易其實模板和泛型是相同的東西盡管它們的實現稍微不同
C#泛型支持在使用點處才定義算法及其數據類型在C#的一些早期版本中我們可以證明沒有泛型也可以工作因為每種類型都是派生於一個公共基類型object這意味著程序員可以基於object類型定義一個棧類並且把一切東西放到該棧上(因為一切都派生於object)然而一個object棧意味著Customer對象Integer對象以及假想的對象都能被放置到同一個棧的實例上結果是開發者要子類化數據類型來把數據類型綁定到他們要與之交互的東西上去例如在編寫定制的商業對象時我們就建議定義派生於SystemCollectionsCollectionBase的強類型集合原因很簡單基於object定義一切被認為是弱類型定義
業界的高手們在數十年前就確信強類型優於弱類型所以NET最終支持強類型這看上去是很自然的事情強類型算法當然建議類型化參數這正是我們在泛型中所用的東西
十幾年來我們一直在使用字母T作為類型化參數的名字這樣在任何泛型類使用者所提供的數據類型的地方你都能夠找到T使用泛型的關鍵僅僅是提供這個T定義泛型的關鍵在於實現一個方法或類並且用特定數據類型來替換掉T
C#中的泛型支持另外一些提煉例如一個方法或類可以有多個參數化的類型並且C#泛型還支持WHERE約束它用來具體要求類型化參數的類型例如如果一個泛型類型必須實現接口IDisposable那麼C#泛型是支持實現這一限制的在文章的最後我們還要看一下約束問題
閒話少說讓我們言歸正傳
二 使用泛型集合
有些人問我面向對象編程(OOP)的承諾在哪裡?我的回答是應該從兩個方面來看OOP你所使用的OOP和你創建的OOP如果我們簡單地看一下如果沒有如例如Microsoft的NETBorland的VCL以及所有的第三方組件這樣的OO框架那麼很多高級的應用程序幾乎就無法創建所以我們可以說OOP已經實現了它的承諾不錯生產好的OOP代碼是困難的並且可能是極具挫敗性的但是記住你不必須一定要通過OOP來實現你的目標因此下面首先讓我們看一下泛型的使用
當你用Visual Studio或C# Express等快速開發工具創建工程時你會看到對於SystemCollectionsGeneric命名空間的參考引用在這個命名空間中存在若干泛型數據結構它們都支持類型化的集合散列隊列棧字典以及鏈表等為了使用這些強有力的數據結構你所要做的僅是提供數據類型
列表顯示出我們定義一個強類型集合的Customer對象是很容易的
列表 這個控制台應用程序包含一個Customer類和一個基於List<T>的強類型集合Customers
using System;
using SystemCollectionsGeneric;
using SystemText;
namespace Generics{
class Program{
static void Main(string[] args){
List<Customer> customers = new List<Customer>();
customersAdd(new Customer(MotownJobs));
customersAdd(new Customer(Fatmans));
foreach (Customer c in customers)
ConsoleWriteLine(cCustomerName);
ConsoleReadLine();
}
}
public class Customer{
private string customerName = ;
public string CustomerName{
get { return customerName; }
set { customerName = value; }
}
public Customer(string customerName){
thiscustomerName = customerName;
}
}
}
注意我們有一個強類型集合List<Customer>對這個集合類本身來說不需要寫一句代碼如果我們想要擴展列表customer我們可以通過從List<Customer>繼承而派生一個新類
三 實現一個泛型類
一種合理的實現某種新功能的方法是在原有的事物上進一步構建我們已經了解強類型集合並知道一種不錯的用來構建泛型類的技術是使用一個特定類並刪除數據類型也就是說讓我們定義一個強類型集合CustomerList並且來看一下它要把什麼東西轉化成一個泛型類
列表定義了一個類CustomerList後面的部分把CustomerList轉化成List<T>
列表定義類CustomerList:
using System;
using SystemCollections;
using SystemText;
namespace Generics{
public class CustomerList : CollectionBase{
public CustomerList() { }
public Customer this[int index]{
get { return (Customer)List[index]; }
set { List[index] = value; }
}
public int Add(Customer value)
{return ListAdd(value);}
}
}
四 定義類頭
如果我們定義一個泛型類我們需要把類頭轉化成一個泛型類所有我們需要做的是命名參數並且把類名改成某種泛型List<T>只有一個參數T並且因為我們在以一種向後兼容的方式工作所以我們知道類名是List列表顯示出列表中類的新類頭
列表 一個泛型類頭顯示出參數化的參數T
using System;
using SystemCollections;
using SystemText;
namespace Generics{
public class List<T> : CollectionBase {}
五 實現泛型字段
如果我們需要把任何字段轉換成泛型字段我們將只需簡單地把它們的類型改變成T(或該字段所描述的任何參數)泛型List不需要任何字段但是假定存在一個私有的整型字段叫foo我們將把它泛型化我們將如下重新定義它:
private T foo;
當參數T被填充到類中時List T也將因foo被填充
六 定義泛型方法
接下來我們為所需要的參數化類型定義其它一些特性這包括屬性方法和事件在我們的實例中在Customer出現的每一處我們都用參數T替換它完成後的泛型列表類顯示於列表中
列表 一個基於SystemCollectionsCollectionBase的輕量級的參數化泛型列表類
using System;
using SystemCollections;
using SystemText;
namespace Generics{
public class List<T> : CollectionBase {
public List(){ }
public T this[int index] {
get { return (T)List[index]; }
set { List[index] = value; }
}
public int Add(T value) {
return ListAdd(value);
}
}
}
為了測試該定制列表注釋掉使用SystemCollectionsGeneric命名空間一句並且把列表中的List<T>使用在列表的代碼中它將以同樣的方式工作
全面地修改NET的List<T>是不必要的而且它也包含遠比我們的示例多得多的特性但是列表顯示出這種機制對於定義定制泛型類是多麼容易
七 增加類型約束
最後要討論的是約束問題約束被應用於類或其它特性上並且使用下面的語法
Where T : constraint_type
例如任何我們想要通過using語句所使用的如一個SqlDataReader必須實現Idisposable接口這是因為如下方式使用的using語句:
using(Form f = new Form()){}
就象一個tryfinally塊一樣工作總是清除新創建的資源其工作原理很簡單只需要CLR針對在該using語句中創建的對象發出一個到IDisposableDispose的調用即可例如在上面這一句中一個新的表單被創建並且在using語句退出之前即調用FormDispose
要對一個泛型類施加以確保該類實現了接口IDisposable我們將添加先行詞where T:Idisposable在列表中的泛型列表上施加約束後我們將重新修改列表如下面的列表所示
列表 增加一個約束到泛型類以確保我們的List<T>中的所有的值T實現接口Idisposable
using System;
using SystemCollections;
using SystemText;
namespace Generics{
public class List<T> : CollectionBase where t : IDisposable{
public List(){ }
public T this[int index]{
get { return (T)List[index]; }
set { List[index] = value; }
}
public int Add(T value){return ListAdd(value);}
}
}
先行詞where的值可以是類接口結構實現一個無參的公共構造器或有一個特定的基類的類詳見有關幫助文檔
八 總結
泛型的設計是用來減少你重復實現的代碼的次數只需改變數據類型即可因為抽象數據結構如隊列棧和列表皆是典型的數據結構所以存在針對這些東西的泛型類完全可以理解你可以從NET中派生大量的值通過使用現有的泛型類如在SystemCollectionsGeneric命名空間中的那些
可以肯定在一段相當長的時間裡泛型將會象模式和重構等革新一樣對開發帶來越來越大的價值而且新的數據結構能被轉換成可重用的如泛型等的代碼元素
From:http://tw.wingwit.com/Article/program/net/201311/13393.html