.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 本节内容为类的多态与继承 简介 终于讲到了面向对象三大特性中的两大特性--继承与多态.通过继承与多态,我们能很好的将类的拓展性发挥到了极致.在下面的内容 ...
随机推荐
- ElasticSearch2.3.1环境搭建哪些不为人知的坑
首先说明一点,大家最好不要用什么尝鲜版,用比稳定版就好了,要不麻烦不断,另外出了问题,最好去官网,或者google搜索,因为这样靠谱些,要不现在好多都是低版本的,1.4的什么的,结果按照安装,多少情况 ...
- gitlab安装笔记二_Centos7配置163yum源
进入配置目录 cd /etc/yum.repos.d 压缩备份原有的配置 sudo tar cvf base.tar.gz *.repo 可以解压查看备份 sudo tar xvf base. ...
- 视频技术详解:RTMP H5 直播流技术解析
本文聚焦 RTMP 协议的最精华的内容,接进行实际操作 Buffer 的练习和协议的学习. RTMP 是什么 RTMP 全称即是 Real-Time Messaging Protocol.顾名思义就是 ...
- 每周分享五个 PyCharm 使用技巧(五)
文章首发于 微信公众号:Python编程时光 大家好,这是本系列 PyCharm 的高效使用技巧的第五篇.按照惯例,本次还是分享 5 个. 本系列前四篇如下,若还没看的,你可以点击查阅 21. 随处折 ...
- 手动实现一个 IOC/DI 容器
第一章为源码解析. 第二章为实现一个简单的 IOC 容器. 第三章进阶 Spring 插件开发. 手动实现一个 IOC/DI 容器 上一篇文章里我们已经对 Spring 的源码有了一个大概的认识,对于 ...
- 【工具】java 文本文档txt写出记录工具
彩蛋!http://abowman.com/google-modules/dog/ 以下是自己小游戏生成人物经历的传记时保存txt所用到的工具类,功能简单,不多说什么,贴上代码: package co ...
- 如何使用JavaScript导入和导出Excel文件
本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. JavaScript是一个涵盖多种框架.直译式.可以轻松自定义客户端的脚本 ...
- web交互方式---ajax
知识不怕旧,关键在于在旧知识的基础上不断创新与提高! 引入一个问题:打开一个浏览器,在地址栏输入一个网址,按下 enter 键到看到整个页面,中间都经历了哪些事情? 这是一个前端的面试题,相信很多朋友 ...
- java html中文汉字 反转义
import org.apache.commons.lang.StringEscapeUtils; public class EscapeHtml { /** * @param args */ pub ...
- MYSQL5.7---ONLY_FULL_GROUP_BY 异常处理
异常介绍: ONLY_FULL_GROUP_BY 指的是你查询的语句使用到了group by 例如 select name,age from person group by sex; 此时你grou ...