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

    装箱(boxing):将值类型转换为引用类型。

    拆箱(unboxing):将引用类型转换为值类型。

    c#数据类型分:值类型简单类型(布尔类型 字符类型 实数类型) 结构类型struct  枚举类型enum】 , 引用类型接口类型interface  所有的数组 类类型class 委托delegate】  指针类型

    在拆箱的过程中要注意以下两点:

    1. 如果对已装箱的值类型的引用的变量为null,会引发NullRefreenceException异常

    2. 如果一个引用指向的对象在拆箱时不是用的装箱时所使用的类型,将会引发InvalidCastException异常。代码如下:

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 Object o = x; 
    5 Int16 y = (Int16)o; //引发InvalidCastException异常
    6 }
    7


    正确的做法是,现将其用Int32类型来拆箱,然后再强制转换为Int16

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 Object o = x; 
    5 Int16 y = (Int16)(Int32)o; 
    6 }
     

    下面来看两段程序来深入理解下装箱和拆箱

    代码一:

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 Object o = x; 
    5 x = 123; 

    7 Console.WriteLine(x + ", " + (Int32)o); 
    8 }
    9


    上面的代码中有多少次装箱呢?乍一看好像就一次(Object o=x;),其实一共有三次装箱,看看IL代码就一目了然了。

    程序的执行步骤:

    1 创建一个Int32的未装箱的值类型实例x,并初始化为5.

    2 创建Object类型的变量o,并指向x。由于引用类型的变量必须要执行堆中的对象,所以要对x进行装箱(第一次装箱),并将x在堆中的引用地址存储在o中。

    3 将值123赋给未装箱的值类型实例x中。

    4 调用WriteLine方法,WriteLine方法的参数值类型为String,现在WriteLine方法存在三个数据项,值类型x、string类型“,”和一个已装箱的Int32类型实例的引用o,这三个数据项必须要合并成一个string对象才能被调用。

    5 调用String对象的静态方法Concat,Concat方法有9个重载,根据那三个数据项会选择下面方法执行。

    6 第一个参数arg0传入的是x ,参数类型为object,所以要对x进行装箱(第二次装箱),将引用地址传给arg0,arg1传入的是字符串“,”,字符串就是引用类型,直接传引用地址,arg2传入的是将o拆箱然后再装箱(第三次装箱)的引用地址传入。

    上面代码中的WriteLine方法如果直接写成Console.WriteLine(x + ", " + o); 将会有跟高的相率,因为o本身就是Object类型,在Concat的时候不用进行装箱拆箱。

    代码二:看看这段程序发生了几次装箱

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 Object o=x; 
    5 x=123; 
    6 Console.WriteLine(x); 
    7 x = (Int32)o; 
    8 Console.WriteLine(x); 
    9 Console.WriteLine(o); 
    10 }
    11


    上面的代码只发生了一次装箱,因为WriteLine方法的重载版本中参数类型可以为Objet或是Int32,在调用WriteLine方法是并没有装箱,唯一的一次装箱是Object o=x; 。

    代码三:

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 CheckRef(x, x); //输出不同引用
    5 }

    7 static void CheckRef(object obj1, object obj2)
    8 {
    9 if (obj1 == obj2)
    10 Console.WriteLine("相同引用"); 
    11 else
    12 Console.WriteLine("不同引用"); 
    13 }
    14

    1 static void Main(string[] args)
    2 {
    3 Int32 x = 5; 
    4 Object o = x; 
    5 CheckRef(o,o); //输出相同引用
    6 }

    8 static void CheckRef(object obj1, object obj2)
    9 {
    10 if (obj1 == obj2)
    11 Console.WriteLine("相同引用"); 
    12 else
    13 Console.WriteLine("不同引用"); 
    14 }
    15

    执行上面代码将发生两次装箱,因为CheckRef方法的两个参数都是Object类型,传入的都是值类型的实例,可以讲代码改进下,先将x转换成Object类型再传入方法,如下:

    改进后只进行一次装箱操作了,效率提高了,但是会发现运行的结果页发生了变化,所以这种做法在有些时候是很危险的。

    装箱拆箱操作极大的破环程序的性能,不过在Net2.0中提供了泛型集合类,所以完全可以用List 和Dictionary 来代替 原来1.0中的ArrayList和HashTable,即使是List也会比ArrayList的性能要好。

  • 相关阅读:
    SpringCloud系列——TX-LCN分布式事务管理
    SpringCloud系列——限流、熔断、降级
    SpringBoot系列——Logback日志,输出到文件以及实时输出到web页面
    常用的js、java编码解码方法
    WebSocket数据加密——AES与RSA混合加密
    使用Fiddler重定向App的网络请求
    C# 调用 taskkill命令结束服务进程
    Install .Net Core For CentOS
    cron表达式详解[转]
    WinServer远程部署系统打包批处理文件
  • 原文地址:https://www.cnblogs.com/ShaYeBlog/p/3231773.html
Copyright © 2011-2022 走看看