從裝箱拆箱看泛型

.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
IL Code

發現並沒拆裝箱過程,說明泛型能提供類型安全的類並能提供應用程序的性能,基於以上幾點在訪問數據層常用泛型以期提升代碼的重用性,在數據訪問泛型類一般須要調用泛型類型中的方法,因此必須給泛型類添加約束,泛型支持幾種約束以下: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; }
    }

總結泛型類能夠建立獨立於類型的類,泛型方法是獨立於類型的方法,接口結構和委託也能夠用泛型的方式建立。

相關文章
相關標籤/搜索