C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

一:值类型和引用类型的含义参考前一篇文章

  C#学习笔记(基础知识回顾)之值类型和引用类型

  1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型。如果int只不过是栈上的一个4字节的值,该如何在它上面调用方法?

二:值类型转换为引用类型——装箱

  2.1CLR对值类型进行装箱时:新分配托管堆内存,将值类型的实例字段拷贝到新分配的内存中,返回托管堆中新分配对象的地址。这个地址就是一个指向对象的引用。

int i = 10;
Object obj = i;

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

三:将引用类型转换为值类型——拆箱

  3.1只能对以前装箱的变形进行拆箱,拆箱是将对象转换为原来的类型

int i = 10;
Object obj = i;
int j = (int)obj;

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

四:为什么需要装箱拆箱?

   4.1一种最普通的场景是,调用一个含类型为Object的参数的方法,该Object可支持任意为型,以便通用。当你需要将一个值类型传入时,需要装箱。例如:AddOne接收一个Object类型参数,如果是int32类型则数值加1,如果是string类型则加字符串“1”。

static void Main(string[] args)
        {
            int i = 10;
            string str = "10";
            Console.WriteLine(AddOne(i));//输出11
            Console.WriteLine(AddOne(str));//输出101
            Console.ReadKey();
        }
        public static string AddOne(Object o)
        {
            if (o.GetType() == typeof (Int32))
            {
                return ((int) o + 1).ToString();
            }
            else if(o.GetType()==typeof(String))
            {
                return o+ "1";

            }
            else
            {
                return "1";
            }
        }

  4.2另一种用法是,一个非泛型的容器,同样是为了保证通用,而将元素类型定义为Object。于是,要将值类型数据加入容器时,需要装箱。例如:

var array = new ArrayList();
            array.Add(1);
            array.Add("2");

            foreach (var value in array)
            {
                Console.WriteLine("value is {0}", value);
            }
            //结果输出是:value is 1
            //            value is 2
            Console.ReadKey();

五:装箱拆箱的性能影响

从原理上可以看出,装箱时,生成的是全新的引用对象,这会有时间损耗,也就是造成效率降低。 
所以,应该尽量避免装箱。 

比如4.1的情况可以通过方法重载避免,4.2尽量使用泛型规避装箱拆箱操作。