.NET很容易把值類型轉換爲引用類型,因此能夠在須要對象的任意地方使用值類型。例如int能夠賦予一個對象,從值類型轉換爲引用類型稱爲裝箱。若是方法須要把一個對象做爲參數,同時傳遞一個值類型,裝箱操做就會自動進行。另外一方面,裝箱的值類型能夠使用拆箱操做轉換爲值類型。node
定義一個通常的、非泛型的簡化鏈表類,它能夠包含任意類型的對象,在鏈表中,一個元素引用下一個元素。因此必須建立一個類,它將對象封裝在鏈表中,並引用下一個對象。類LinkedListNode包含一個屬性Value,該屬性用構造函數初始化。另外LinkedListNode類包含對鏈表中下一個元素和上一個元素的引用,這些元素均可以從屬性中訪問。安全
先定義LinkedListNode類ide
public class LinkedListNode { public LinkedListNode(object value) { this.Value = value; } public object Value { get; private set; } public LinkedListNode Next { get; internal set; } public LinkedListNode Prev { get; internal set; } }
再定義一個非泛型的簡化鏈表類,實現非泛型接口函數
public class LinkedList : IEnumerable { public LinkedListNode First { get; private set; } public LinkedListNode Last { get; private set; } public LinkedListNode AddLast(object node) { var newNode = new LinkedListNode(node); if (First == null) { First = newNode; Last = First; } else { Last.Next = newNode; Last = newNode; } return newNode; } public IEnumerator GetEnumerator() { LinkedListNode current = First; while (current != null) { yield return current.Value; current = current.Next; } } }
用ILSpy查看IL代碼oop
IL_0000: nop IL_0001: newobj instance void PraticeCharter01.LinkedList::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldc.i4.3 IL_0009: box [mscorlib]System.Int32 IL_000e: callvirt instance class PraticeCharter01.LinkedListNode PraticeCharter01.LinkedList::AddLast(object) IL_0013: pop IL_0014: ldloc.0 IL_0015: ldc.i4.4 IL_0016: box [mscorlib]System.Int32 IL_001b: callvirt instance class PraticeCharter01.LinkedListNode PraticeCharter01.LinkedList::AddLast(object) IL_0020: pop IL_0021: nop IL_0022: ldloc.0 IL_0023: callvirt instance class [mscorlib]System.Collections.IEnumerator PraticeCharter01.LinkedList::GetEnumerator() IL_0028: stloc.1 .try { IL_0029: br.s IL_003e // loop start (head: IL_003e) IL_002b: ldloc.1 IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() IL_0031: unbox.any [mscorlib]System.Int32 IL_0036: stloc.2 IL_0037: ldloc.2 IL_0038: call void [mscorlib]System.Console::WriteLine(int32) IL_003d: nop IL_003e: ldloc.1 IL_003f: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() IL_0044: brtrue.s IL_002b // end loop IL_0046: leave.s IL_005a } // end .try
分析IL代碼可知上述過程發生了兩次裝箱和兩次拆箱,在foreach語句中,鏈表中的元素被強制轉換爲整形,裝箱和拆箱操做很容易使用,但性能損失比較大,泛型能很好的避免拆裝箱,從而提供性能。性能
再定義一個泛型版本,該泛型集合實現泛型接口IEnumeratorthis
public class LinkedListNode<T> { public LinkedListNode(T value) { this.Value = value; } public T Value { get; private set; } public LinkedListNode<T> Next { get; internal set; } public LinkedListNode<T> Prev { get; internal set; } } public class LinkedList<T> : IEnumerable<T> { public LinkedListNode<T> First { get; private set; } public LinkedListNode<T> Last { get; private set; } public LinkedListNode<T> AddLast(T node) { var newNode = new LinkedListNode<T>(node); if (First == null) { First = newNode; Last = First; } else { Last.Next = newNode; Last = newNode; } return newNode; } public IEnumerator<T> GetEnumerator() { LinkedListNode<T> current = First; while (current != null) { yield return current.Value; current = current.Next; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
static void Main(string[] args) { var list = new LinkedList<int>(); list.AddLast(3); list.AddLast(4); foreach (int element in list) Console.WriteLine(element); Console.ReadKey(); }
查看IL代碼spa
IL_0000: nop IL_0001: newobj instance void class PraticeCharter01.LinkedList`1<int32>::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldc.i4.3 IL_0009: callvirt instance class PraticeCharter01.LinkedListNode`1<!0> class PraticeCharter01.LinkedList`1<int32>::AddLast(!0) IL_000e: pop IL_000f: ldloc.0 IL_0010: ldc.i4.4 IL_0011: callvirt instance class PraticeCharter01.LinkedListNode`1<!0> class PraticeCharter01.LinkedList`1<int32>::AddLast(!0) IL_0016: pop IL_0017: nop IL_0018: ldloc.0 IL_0019: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class PraticeCharter01.LinkedList`1<int32>::GetEnumerator() IL_001e: stloc.1 .try { IL_001f: br.s IL_002f // loop start (head: IL_002f) IL_0021: ldloc.1 IL_0022: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() IL_0027: stloc.2 IL_0028: ldloc.2 IL_0029: call void [mscorlib]System.Console::WriteLine(int32) IL_002e: nop IL_002f: ldloc.1 IL_0030: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() IL_0035: brtrue.s IL_0021 // end loop IL_0037: leave.s IL_0044 } // end .try
發現並沒拆裝箱過程,說明泛型能提供類型安全的類並能提供應用程序的性能,基於以上幾點在訪問數據層常用泛型以期提升代碼的重用性,在數據訪問泛型類一般須要調用泛型類型中的方法,因此必須給泛型類添加約束,泛型支持幾種約束以下:3d
(1)where T:struct 對於結構約束,類型T必須是值類型code
(2)where T:class 類約束指定類型T必須是引用類型
(3)where T:IFoo指定類型T必須實現接口IFoo
(4)where T:new()這是一個構造函數約束,指定類型T必須有一個默認構造函數
(5)where T1:T2這個約束也能夠指定,類型T1派生自泛型類型T二、該約束稱爲裸約束
定義一個實現IComparable泛型接口的實體
public class EmployeModel:IComparable<EmployeModel> { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public int CompareTo(EmployeModel other) { if (Age > other.Age) return 1; else if (Age.Equals(other.Age)) return 0; else return -1; } }
定義泛型類,該泛型有兩個約束
public class BaseDAL<T> where T : class,IComparable<T> { }
class Program { static void Main(string[] args) { var baseAccess = new BaseDAL<NullableStruct>();//不是引用類型編譯錯誤 var student = new BaseDAL<Student>();//沒有實現IComparable接口 var employeeAccess = new BaseDAL<EmployeModel>(); } } public struct NullableStruct { long longnumber; int intnumber; } public class Student { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } }
總結泛型類能夠建立獨立於類型的類,泛型方法是獨立於類型的方法,接口結構和委託也能夠用泛型的方式建立。