zoukankan      html  css  js  c++  java
  • 装箱拆箱

    从装箱拆箱看泛型

     

    .NET很容易把值类型转换为引用类型,所以可以在需要对象的任意地方使用值类型。例如int可以赋予一个对象,从值类型转换为引用类型称为装箱。如果方法需要把一个对象作为参数,同时传递一个值类型,装箱操作就会自动进行。另一方面,装箱的值类型可以使用拆箱操作转换为值类型。

    定义一个一般的、非泛型的简化链表类,它可以包含任意类型的对象,在链表中,一个元素引用下一个元素。所以必须创建一个类,它将对象封装在链表中,并引用下一个对象。类LinkedListNode包含一个属性Value,该属性用构造函数初始化。另外LinkedListNode类包含对链表中下一个元素和上一个元素的引用,这些元素都可以从属性中访问。

    先定义LinkedListNode类

    复制代码
     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代码

    复制代码
    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语句中,链表中的元素被强制转换为整形,装箱和拆箱操作很容易使用,但性能损失比较大,泛型能很好的避免拆装箱,从而提供性能。

    再定义一个泛型版本,该泛型集合实现泛型接口IEnumerator

    复制代码
    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代码

     IL Code

    发现并没拆装箱过程,说明泛型能提供类型安全的类并能提供应用程序的性能,基于以上几点在访问数据层经常使用泛型以期提高代码的重用性,在数据访问泛型类通常需要调用泛型类型中的方法,所以必须给泛型类添加约束,泛型支持几种约束如下:

    (1)where T:struct 对于结构约束,类型T必须是值类型

    (2)where T:class 类约束指定类型T必须是引用类型

    (3)where T:IFoo指定类型T必须实现接口IFoo

    (4)where T:new()这是一个构造函数约束,指定类型T必须有一个默认构造函数

    (5)where T1:T2这个约束也可以指定,类型T1派生自泛型类型T2、该约束称为裸约束

    定义一个实现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; }
        }
    复制代码

    总结泛型类可以创建独立于类型的类,泛型方法是独立于类型的方法,接口结构和委托也可以用泛型的方式创建。

  • 相关阅读:
    最全前端面试题
    经常犯的思维误区
    鸿蒙系统发布会
    前端面试题
    怎么做一个竖排文字?
    canvas-台球玩法
    canvas-自由落体球
    canvas-画一颗心
    canvas-学写字
    常用的65条正则表达式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/6794536.html
Copyright © 2011-2022 走看看