.NET Core CSharp 中级篇 2-1 装箱与拆箱
.NET Core CSharp 中级篇 2-1
本节内容为装箱与拆箱
简介
装箱和拆箱是一个相对抽象的概念。你可以想象一下一堆满载货物的大卡车,他是由许多工人将货物集中堆放装入的,对于我们而言在没有打开货箱的时候,我们可以知道这是一辆运货的卡车,里面有着许多货物,但是具体货物是什么,我们只有打开后才能知道,并且对于货箱而言,它可以存放任意体积小于自身的货物,也就是说货箱具有通配性。事实上在C#中也是这样,装箱就是将具有实际数据的变量(值类型)打包成一个引用类型(Object),而我们货物到货箱的变化,就是我们本节所需要谈论的装箱与拆箱。利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型与引用类型链接起来。
装箱
装箱是将值类型转换为引用类型,在此前对于基础类型的讲述中,我曾经提到过值类型是在栈中进行分配的,而引用类型是在堆中进行分配,并且需要注意的是,这个堆,是托管堆。托管堆对应于垃圾回收,也就是说用垃圾回收堆中存储值类型。装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。这里的运用一种最普通的场景是,调用一个含类型为Object的参数的方法,该Object可支持任意类型,因为所有类型都隐式的继承于Object类,以便通用。当你需要将一个值类型(如Int32)传入时,需要装箱。另一种用法是,一个非泛型的容器,同样是为了保证通用,而将元素类型定义为Object。于是,要将值类型数据加入容器时,需要装箱。
这是一个非常简单的装箱操作:
double price = 13.53;
object temp = price;
这段代码看似异常的和谐和简单,但是你是否想过这个过程发生了什么呢?
还记得我们在类的生命周期中讲到的类的创建过程吗?装箱事实上是一样的,装箱对值类型在堆中分配一个对象实例,并将该值复制到新的对象中。按三步进行。
- 新分配托管堆内存,值得注意的是,这里内存需要加上方法表指针和SyncBlockIndex指针
- 将值类型的实例字段拷贝到新分配的内存中。
- 返回托管堆中新分配对象的地址。这个地址就是一个指向对象的引用了。
显然,从装箱的过程上可以看出,装箱时,生成了一个全新的引用类型,创建类型必定伴随着相对较大的时间损耗。所以应该尽量避免装箱。通常对于装箱的情形,我们可以通过重载函数或者通过泛型来避免。但是假设你想改造的代码为第三方程序集,你无法更改,那你只能是装箱了。对于装箱的过程,在C#中都是隐式的,如果你想要观察这个过程,我建议你使用dnSpy或者ILSpy进行反编译分析IL代码。
不过装箱看似只是一个损耗性能的操作,偶尔也是有作用的一种最普通的场景是,调用一个含类型为Object的参数的方法,该Object可支持任意为型,以便通用。当你需要将一个值类型(如Int32)传入时,需要装箱。另一种用法是,一个非泛型的容器,同样是为了保证通用,而将元素类型定义为Object。于是,要将值类型数据加入容器时,需要装箱。
并且特别的,对于已装箱的对象,因为无法直接调用其指定方法,所以必须先拆箱,再调用方法,但再次拆箱,会生成新的栈实例,而无法修改装箱对象。这句话我此前学习C#的时候也纠结了一段时间,后来恍然大悟。直白的意思有点类似于你克隆了你自己,和你一模一样,但是你两是同一个人吗?显然不是,你操作克隆人并不会对你有任何的影响。
下面这段代码你可以尝试一下
struct Test
{
public int x;
public void test(int x)
{
this.x = x;
}
}
Test t = new Test();
t.x = 100;
object a = t;//装箱
((Test)a).test(300);//x还是100不变,为什么
拆箱
相对于装箱,将一个引用类型(object)类型转换成值类型的过程就是拆箱,说明确一点就是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。拆箱会检查对象实例,确保它是给定值类型的一个装箱值。将该值从实例复制到值类型变量中。不过我查阅了很多资料,对于拆箱操作,讲的少之又少,我猜测,拆箱过程中,会调用GetType这种方法进行严格的匹配。
double price = 13.53;
object obj = price;
double temp = (double) obj;
这是一个拆箱的过程,是将值类型转换为引用类型,再由引用类型转换为值类型的过程。首先获取托管堆中属于值类型那部分字段的地址,这一步是严格意义上的拆箱。将引用对象中的值拷贝到位于线程堆栈上的值类型实例中。可以认为和装箱是互反操作。严格意义上的拆箱,并不影响性能,但伴随这之后的拷贝数据的操作就会同装箱操作中一样影响性能。
如果我的文章帮到了你,请为我点一个推荐关注,在Github项目页点一颗star,感谢支持
后续我会补上习题以及图片
.NET Core CSharp 中级篇 2-1 装箱与拆箱的更多相关文章
- .NET Core CSharp 中级篇 2-2 List,ArrayList和Dictionary
.NET Core CSharp 中级篇 2-2 本节内容为List,ArrayList,和Dictionary 简介 在此前的文章中我们学习了数组的使用,但是数组有一个很大的问题就是存储空间不足,我 ...
- .NET Core CSharp 中级篇2-8 特性标签
.NET Core CSharp 中级篇2-8 本节内容为特性标签 简介 标签Attribute是一个非常重要的技术,你可以使用Attribute技术优化精简你的代码.特性标签可以运用在程序集,模块, ...
- C# 程序性能提升篇-1、装箱和拆箱,枚举的ToString浅析
前景提要: 编写程序时,也许你不经意间,就不知不觉的使程序代码,发生了装箱和拆箱,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环.网络程序(不断请求处理的)等这些时候,减少装箱和拆 ...
- .NET Core C# 中级篇2-7 文件操作
.NET Core CSharp 中级篇2-7 本节内容为文件操作 简介 文件操作在我们C#里还是比较常见的,例如我们读取Excel.Txt文件的内容,在程序中,这些文件都是以流的方式读取进入我们内存 ...
- NET Core CSharp初级篇 1-3面向对象
.NET Core CSharp初级篇 1-3 本节内容为面向对象初级教程 类 简介 面向对象是整个C#中最核心最有特色的一个模块了,它很好的诠释了程序与现实世界的联系. 面向对象的三大特征:继承.多 ...
- .NET Core CSharp初级篇 1-8泛型、逆变与协变
.NET Core CSharp初级篇 1-8 本节内容为泛型 为什么需要泛型 泛型是一个非常有趣的东西,他的出现对于减少代码复用率有了很大的帮助.比如说遇到两个模块的功能非常相似,只是一个是处理in ...
- .NET Core CSharp初级篇 1-1
.NET Core CSharp初级篇 1-1 本节内容是对于C#基础类型的存储方式以及C#基础类型的理论介绍 基础数据类型介绍 例如以下这句话:"张三是一名程序员,今年15岁重50.3kg ...
- .NET Core CSharp初级篇 1-5 接口、枚举、抽象
.NET Core CSharp初级篇 1-5 本节内容类的接口.枚举.抽象 简介 问题 如果你需要表示星期或者是某些状态,使用字符串或者数字是否不直观? 你是否发现,无论何种电脑,它的USB口的设计 ...
- .NET Core CSharp初级篇 1-6 类的多态与继承
.NET Core CSharp初级篇 1-6 本节内容为类的多态与继承 简介 终于讲到了面向对象三大特性中的两大特性--继承与多态.通过继承与多态,我们能很好的将类的拓展性发挥到了极致.在下面的内容 ...
随机推荐
- React性能优化之PureComponent 和 memo使用分析
前言 关于react性能优化,在react 16这个版本,官方推出fiber,在框架层面优化了react性能上面的问题.由于这个太过于庞大,我们今天围绕子自组件更新策略,从两个及其微小的方面来谈rea ...
- Python自学day-12
一.Mysql概述 RDBMS:关系型数据库管理系统.Mysql是一种RDBMS. Oracle:收费 Mysql:Oracle旗下免费 Sqlserver:微软 DB2:IBM Postgresql ...
- (数据科学学习手札62)详解seaborn中的kdeplot、rugplot、distplot与jointplot
一.简介 seaborn是Python中基于matplotlib的具有更多可视化功能和更优美绘图风格的绘图模块,当我们想要探索单个或一对数据分布上的特征时,可以使用到seaborn中内置的若干函数对数 ...
- 基于cxf开发的WebService
Node.jshttps://www.cnblogs.com/goldlong/p/8027997.htmlQQ音乐apihttps://juejin.im/post/5a35228e51882506 ...
- Requests方法 -- 重定向操作
一.重定向1. (Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置,从地址A跳转到地址 B 了.2.重定向状态码:--301 redirect: 301 代表永久性转移(Per ...
- JAVA Stirng.format 使用理解
JAVA Stirng.format 使用理解前言:项目中需要对一些字符串处理发现format方法的神奇之处一.api才是王道第一种二参使用①public static String format(S ...
- 深入理解Java的switch...case...语句
switch...case...中条件表达式的演进 最早时,只支持int.char.byte.short这样的整型的基本类型或对应的包装类型Integer.Character.Byte.Short常量 ...
- 爬虫之抓js教程
在初学的爬虫过程中,很多人还不知道有些字段是如何生成的,怎样模拟生成这些字段来拼接头部.为了再次纪念[宏彦获水]成语初次面世,特地用[百度登陆]写下一篇登陆百度的教程,以供大家参考. 前面学习了如何在 ...
- 跟我学SpringCloud | 第十四篇:Spring Cloud Gateway高级应用
SpringCloud系列教程 | 第十四篇:Spring Cloud Gateway高级应用 Springboot: 2.1.6.RELEASE SpringCloud: Greenwich.SR1 ...
- 第九章 webase 分布式中间件平台快速部署
鉴于笔者以前各大博客教程都有很多人提问,早期建立一个技术交流群,里面技术体系可能比较杂,想了解相关区块链开发,技术提问,请加QQ群:538327407 参考资料:https://webasedoc.r ...