范型是提高面向對象程序多態性設計衍生的。
1,C# 多態性設計回顧和展望
在引入范型這個概念之前,回顧一下1.0或1.1中關於的Object類型的定義:
Object類型是.Net Framework中System.Object的一個別名,可以分配任何類型給Object類型的變量。
通過object類型的引入,實現了.Net對於面向對象程序多態設計。
因為Object本身是一個引用類型,是存放在Heap(堆)上的。對於其他引用類型和Object轉換很容易實現。
而值類型和Object類型轉換需要引入兩個用於object類型和值類型轉換概念boxing和unboxing.
(1)boxing 裝包
將轉換一個值類型到Object類型,
例如:int i = 1; //存儲在棧上
object o = (object) i;//存儲在堆上
上面的代碼在IL中將會是box [mscorlib]System.Int32
將Int32和1同時裝入一個Object對象中,結構如下:
object[{Int32}-{1}];//前者表示boxing類型,後者表示其值
(2)unboxing 拆包
將一個已裝包為Obect類型的值類型轉換回值類型
操作分為兩部分組成:
a,首先檢查是否轉換回的類型是裝包的類型,如果不是拋出一個InvalidCastException運行時錯誤.
b,復制Object類型中的值到目標值類型變量;
例如:
int i = 1;
object o = (object) i; //boxing
int j = (int)o //unboxing
//double d = (double)o ,出現運行時錯誤
通過上面的可以看到在.Net Framework 1.0 中使用object對象設計的多態性比C++的template(一種基於類似宏的編
譯時替換)執行效率增加了大量的copy的開銷。所以在.Net Framewrok 2.0中引入范型來提高高面向對象程序多態性
設計。
2,范型概念和特點:
范型的設計是為了解決上面提到過的Object的多態性設計中的兩個問題:
(1),性能上面的,boxing和unboxing需要大量的復制開銷;
(2),安全性上面的,在上面一個例子看到了如果unboxing類型不同會拋出一個InvalidCastException異常;
范型的設計格式是使用<和>封閉其中一個范型參數,例如:
public class Stack<T>;
范型的實例化格式是使用需要使用的類型替換<和>封閉其中一個范型參數,例如:
Stack<char> char_Stack = new Stack<char>();
多范型類定義格式,在<和>封閉多個范型參數,例如:
class Node<K,T>
對於C++程序員,看上面關於范型的格式很快聯系到了ISO C++當中的Template;
的確兩者語法上面非常相似,但是兩者的多態性編譯和實現有很大不同.
在C++的Template編譯後,沒有編譯帶有Template的代碼.而是通過一種宏的方式進行的替換過程.
每次使用Template類型,編譯器都會生成一個對應的類型代碼.而不管是否個類型代碼已經使用過了.
在C#2.0中范型是在中間語言(IL)和公共語言運行時(CLR)支持的.
對於值類型:會在JIT編譯時候替換參數類型,如果存在以及編譯特定類型的機器代碼,將直接返回這段代碼.
這樣避免了在ISO C++中Template可能帶來代碼膨脹.
對於引用類型:會直接在JIT編譯時候替換參數類型.
理解C# 2.0范型是在實現是基於CLR支持的很重要啊,因為.Net的本質是和語言無關的.任何語言最後都是編譯為中
間語言,這樣基於IL和CLR支持的范型可以運用到所有基於CLR實現的語言,例如:Visual Basic 2005等等.
3,范型和其他類型執行效率對比例子
下面分別是使用Int,Object和范型構造的3個棧的類
/// <summary>
/// Int類型實現的棧
/// </summary>
class IntStack
{
private int[] data;
private int current;
private int length;
public IntStack(int Length)
{
length = Length;
current = 0;
data = new int[length];
}
public int Top()
{
return data[current - 1];
}
public void Push(int Data)
{
if (current < length)
{
data[current++] = Data;
}
}
public void Pop()
{
if (current > 0)
{
current--;
}
}
}
/// <summary>
/// 范型的棧
/// </summary>
/// <typeparam name="T">范型</typeparam>
class TemplateStack<T>
{
private int length;
private int current;
private T[] data;
public TemplateStack(int Length)
{
current = 0;
length = Length;
data = new T[length];
}
public T Top()
{
return data[current - 1];
}
public void Push(T Data)
{
if (current < length)
{
data[current++] = Data;
}
}
public void Pop()
{
if (current > 0)
{
current--;
}
}
}
/// <summary>
/// Object的棧
/// </summary>
class ObjectStack
{
private object[] data;
private int current;
private int length;
public ObjectStack(int Length)
{
length = Length;
; current = 0;
data = new object[length];
}
public object Top()
{
return data[current-1];
}
public void Push(object Data)
{
if (current < length)
{
data[current++] = Data;
}
}
public void Pop()
{
if (current > 0)
{
current--;
}
}
}
通過測試直接使用Int的棧和范型構造Int棧的開銷接近.
而比較前面兩個Object每增加一次unboxig開銷是增加的2倍.
4,附錄.Net 2.0 Framework 范型容器列表:
Comparer<T> Comparer 比較
Dictionary<K,T> HashTable hash表
LinkedList<T> LinkList 鏈表
List<T> ArrayList 數組鏈表
Queue<T> Queue 隊列
SortedDictionary<K,T> SortedList 排序鏈表
Stack<T> Stack 棧
ICollection<T> ICollection 容器接口
IComparable<T> System.IComparable比較接口
IDictionary<K,T> IDictionary 字典接口
IEnumerable<T> IEnumerable 枚舉接口
IEnumerator<T> IEnumerator 跌代接口
IList<T> IList 鏈表接口
參考資料:
《Design and Implementation of Generics for the .Net Common Language Runtime》
---Andrew Kennedy Don Syme (Microsoft Research, Cambridge, U.K.)
《An Introduction to C# Generics》
---Juval Lowy IDesign (MSDN Online)
《C# Programmer''s Reference》
---MSDN Library (MSDN Online)