泛型的优势
假設(shè)需要一個(gè)兩個(gè)整形變量交換的函數(shù),我們很快就可以嗒嗒嗒嗒的敲出下面的 Swap 函數(shù):
?
void Swap(ref int lhs, ref int rhs)
{
??? int temp = lhs;
??? lhs = rhs;
??? rhs = temp;
}
?
隨著項(xiàng)目進(jìn)展,我們發(fā)現(xiàn),需要用到 Swap 函數(shù)的不僅是整形,變量 還有字符串,于是我們我又嗒嗒嗒嗒的重載 Swap 函數(shù)如下:
?
void Swap(ref string lhs, ref string rhs)
{
??? string temp = lhs;
??? lhs = rhs;
??? rhs = temp;
}
?
接下來(lái)的開(kāi)發(fā)中,我們又發(fā)現(xiàn)還有自定義的結(jié)構(gòu)體,類(lèi)等等等等都要用到 Swap 函數(shù)。如果我們?yōu)槊恳环N類(lèi)型都實(shí)現(xiàn)一個(gè)相應(yīng)的 Swap 函數(shù)的話(huà),各個(gè)版本的 Swap 函數(shù)數(shù)據(jù)類(lèi)型不同外,其它完完全全一樣。也就是說(shuō),項(xiàng)目中存在大量的代碼重復(fù)。能不能之實(shí)現(xiàn)一個(gè)能夠適用于不同數(shù)據(jù)類(lèi)型的 Swap 函數(shù),消除這種代碼冗余,從而減少工作量,提高開(kāi)發(fā)效率呢?
類(lèi)型轉(zhuǎn)換
在 C# 中 所有的類(lèi)型都直接或間接的繼承自 System.Object 類(lèi)。換句話(huà)說(shuō),所有的類(lèi)型都可以轉(zhuǎn)換為 Object 類(lèi)。這為我們前面的問(wèn)題提供了一個(gè)解決方案——實(shí)現(xiàn)一個(gè)以 Object 為類(lèi)型參數(shù)的 Swap 函數(shù)。其實(shí)現(xiàn)如下:
?
void Swap(ref object lhs, ref object rhs)
{
??? object temp = lhs;
??? lhs = rhs;
??? rhs = temp;
}
?
調(diào)用的代碼如下:
//a, b 為要傳入 Swap 函數(shù)的變量
object objA = a;
object objB = b;
?
Swap(ref objA, ref objB);
?
//T 為變量 a 和 b 的數(shù)據(jù)類(lèi)型
a = (T)objA;
b = (T)objB;
?
這一實(shí)現(xiàn)利用類(lèi)型轉(zhuǎn)換有效的重用了 Swap 的代碼,但有兩點(diǎn)不足。
?
首先是性能問(wèn)題。每次調(diào)用 Swap 函數(shù)前,需要對(duì)其參數(shù)進(jìn)行一次向上的轉(zhuǎn)型;調(diào)用完之后,又要對(duì)其進(jìn)行一次向下的轉(zhuǎn)型。如果需要多次調(diào)用 Swap 函數(shù)(比如在一個(gè)很大的循環(huán)中),轉(zhuǎn)型帶來(lái)的開(kāi)銷(xiāo)是想當(dāng)可觀的,特別是當(dāng)參數(shù)為值類(lèi)型的時(shí)候。
?
第二是,無(wú)法提供編譯時(shí)類(lèi)型檢查。下面的例子雖然能通過(guò)編譯,但運(yùn)行時(shí)會(huì)出現(xiàn)異常:
?
string a? = “This is a string”;
int b = 0;
?
object objA = a;
object objB = b;
?
Swap(ref objA, ref objB);?????????????? //可以編譯
?
a = (string)objA;?????????????? //出現(xiàn)運(yùn)行時(shí)異常
b = (ing)objB;
?
針對(duì)以上兩點(diǎn)不足,C# 2.0 提出了泛型。
泛型
泛型是C# 2.0 提供的延遲類(lèi)和函數(shù)中數(shù)據(jù)類(lèi)型的定義,直到客戶(hù)代碼聲明或?qū)嵗摂?shù)據(jù)類(lèi)型。
?
泛型版的 Swap 函數(shù)實(shí)現(xiàn)如下
?
void Swap<T>(ref T lhs, ref T rhs)
{
??? T temp = lhs;
??? lhs = rhs;
??? rhs = temp;
}??????? ?
?
泛型集合中的 <T>是obj類(lèi)型
上例中的類(lèi)型參數(shù) T 可以實(shí)例化為任意數(shù)據(jù)類(lèi)型。相對(duì)于通過(guò)類(lèi)型轉(zhuǎn)換重用 Swap 函數(shù),它且不需要類(lèi)型轉(zhuǎn)換,有效的提高性能。而且,它還能提供編譯時(shí)類(lèi)型檢查。調(diào)用語(yǔ)法與普通函數(shù)調(diào)用完全一樣。
泛型的優(yōu)勢(shì)
從上面例子可以看出,使用泛型具有如下三點(diǎn)優(yōu)勢(shì):
?
??????? 避免重復(fù)代碼,最大化代碼重用
??????? 避免無(wú)謂的類(lèi)型轉(zhuǎn)換,提高性能
??????? 提供編譯時(shí)類(lèi)型檢查,具有類(lèi)型安全性
C# code
// 在三角符號(hào)里寫(xiě)入類(lèi)型參數(shù)T
public class GenericList<T>
{
// Node為非泛型類(lèi),作為GenericList<T>的嵌套類(lèi)
private class Node
{
// 在非泛型構(gòu)造函數(shù)中使用T
public Node(T t)
{
next = null;
data = t;
}
private Node next;
public Node Next
{
get { return next; }
set { next = value; }
}
// T作為私有成員的數(shù)據(jù)類(lèi)型
private T data;
// T作為屬性的返回類(lèi)型
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
// 構(gòu)造函數(shù)
public GenericList()
{
head = null;
}
// T 作為方法的參數(shù)類(lèi)型
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
public IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
下面的代碼示例演示客戶(hù)端代碼如何使用泛型 GenericList <T> 類(lèi)來(lái)創(chuàng)建整數(shù)列表。只需更改類(lèi)型參數(shù),即可方便地修改下面的代碼示例,創(chuàng)建字符串或任何其他自定義類(lèi)型的列表:
C# code
class TestGenericList
{
static void Main()
{
// int 是類(lèi)型變量
GenericList<int> list = new GenericList<int>();
for (int x = 0; x < 10; x++)
{
list.AddHead(x);
}
foreach (int i in list)
{
System.Console.Write(i + " ");
}
System.Console.WriteLine("\n完成");
}
}
泛型也在用在類(lèi)里,可以對(duì)參數(shù)進(jìn)行約束而對(duì)于new約束而言有點(diǎn)特殊
{
????public?void?Add(K?key,?V?value)
????{
????????
????????if?(key.CompareTo(x)?<?0)?{}
????????
????}
}
這樣就保證了任何為K類(lèi)型參數(shù)提供的類(lèi)型都實(shí)現(xiàn)了IComparable接口。所以我們的key就可以使用CompareTo方法了。
如果我們?cè)谑褂脮r(shí)提供了沒(méi)有實(shí)現(xiàn)IComparable接口的類(lèi)型,就會(huì)出現(xiàn)編譯時(shí)錯(cuò)誤。
對(duì)于new()約束,大家可能有一個(gè)誤解,以為使用了new約束之后,在創(chuàng)建對(duì)象時(shí)與非泛型的版本是一致的:publicclassTester<T>
whereT:new()
{
publicTester()
{
t=newT();//等同于非泛型版本的new?例如objecto=newobject();?
}
privateTt;
}
事實(shí)上,使用new關(guān)鍵字的作用只是讓編譯器在泛型實(shí)例化之處,檢查所綁定的泛型參數(shù)是否具有無(wú)參構(gòu)造函數(shù):
Tester<SomeType>t=newTester<SomeType>();
//此處編譯器會(huì)檢查SomeType是否具有無(wú)參構(gòu)造函數(shù)。若沒(méi)有則會(huì)有compileerror
?
轉(zhuǎn)載于:https://www.cnblogs.com/dewin/archive/2009/06/28/1512868.html
總結(jié)
- 上一篇: COM, COM+ and .NET 的
- 下一篇: BSTR、char* 和 CString