C#装箱拆箱机制详解

        在C#中,装箱(Boxing)拆箱(Unboxing) 是值类型与引用类型之间转换的核心机制。它们的实现直接影响程序的性能和类型安全。

一、装箱(Boxing)

定义:

值类型转换为引用类型(通常是object或接口类型)的过程

过程:

  1. 堆(Heap)中分配内存,用于存储值类型的副本
  2. 栈(Stack)上的值类型数据复制到堆中
  3. 返回堆中新对象的引用

示例

int value = 1;
object boxed = value; //装箱操作

常见场景

  • 将值类型添加到非泛型集合(如ArrayList)
  • 调用接受object参数的方法时传递值类型

特殊场景

1.Nullable类型(T?)的装箱

  • 如果Nullable<T>的值为null,装箱结果为null
  • 如果有值(如int?i = 1),则装箱其基础类型为(int

2.枚举类型(Enum)的装箱

枚举值会被装箱为底层类型(如int )的实例

性能影响:

  • 堆内存分配和复制操作会带来性能开销
  • 频繁装箱(如循环中)可能会导致内存压力,触发垃圾回收(GC)

二、拆箱

定义:

引用类型(已装箱的值)转换回原始值类型的过程,拆箱的本质是从堆中逐字节复制原始值类型数据到栈

过程:

  1. 检查引用类型是否与目标值类型兼容(否则抛出InvalidCastException)
  2. 将堆中存储的值复制到栈上的值类型变量中

示例

object boxed = 1;
int unboxed = (int)boxed; //拆箱操作

错误示例

object boxed = 1;
double d = (double)boxed; // 抛出 InvalidCastException

错误原因

类型兼容性:CLR(公共语言运行时)会验证引用类型是否与目标值类型完全匹配,装箱的是int,拆箱时目标类型必须也是int,否则抛出InvalidCastException

  • 拆箱的本质是从堆中 逐字节复制原始值类型数据 到栈
  • int 和 double 的内存布局不同:
  • int 是 4 字节整数(如 42 的二进制为 0x0000002A
  • double 是 8 字节浮点数(如 42.0 的二进制为 0x4045000000000000
  • CLR 无法直接将 int 的二进制数据当作 double 解析,必须显式转换

错误修正

  1. 拆箱到原始类型(int
  2. 显式类型转换(int → double

修正后代码:

object boxed = 1;
int unboxedInt = (int)boxed;    // 正确拆箱到 int
double d = (double)unboxedInt;  // 再转换为 double// 或者简写为:
double d = (int)boxed;          // 隐式转换为 double

内存结构

托管堆中的对象:  
[对象头] [同步块索引] [int 数据 = 1]  
↑  
boxed 引用指向此处栈上的 unboxed 变量:  
[int 数据 = 1]

关键点

  • 必须显式指定目标类型(强制类型转换)
  • 拆箱失败会抛出异常,需确保类型匹配
  • 拆箱后需要再次复制数据,仍有性能开销

三、性能优化

1.使用泛型集合

如使用(List<T>)替代非泛型集合(ArrayList)避免装箱

List<int> list = new List<int>(); // 无装箱
list.Add(1);

2.利用接口泛型方法避免装箱

例如,使用IEquatable<T>Equals(T other)方法,而不是object. Equals

3.注意ToString和格式化方法:

int i = 1;
Console.WriteLine(i.ToString()); // 避免装箱(直接调用值类型的ToString)
Console.WriteLine($"{i}"); // 隐式调用 i.ToString(),避免装箱

4.避免在循环或高频代码中装箱/拆箱

5.使用isas安全检查后再拆箱

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 8.4 SQL 全攻略:所有知识点与实战场景

一、引言 MySQL 作为一款广泛使用的开源关系型数据库管理系统&#xff0c;在数据存储和管理领域占据着重要地位。MySQL 8.4 版本在性能、功能和安全性等方面都有了显著的提升。本文将全面介绍 MySQL 8.4 中 SQL 的各种知识点&#xff0c;并结合实战场景进行详细讲解&#xff0…

Qt监控系统远程回放/录像文件远程下载/录像文件打上水印/批量多线程极速下载

一、前言说明 在做这个功能的时候&#xff0c;着实费了点心思&#xff0c;好在之前做ffmpeg加密解密的时候&#xff0c;已经打通了极速加密保存文件&#xff0c;主要就是之前的类中新增了进度提示信号&#xff0c;比如当前已经处理到哪个position位置&#xff0c;发个信号出来…

超高速工业相机的应用

超高速工业相机一般安装在机器流水线上代替人眼来做测量和判断&#xff0c;通过数字图像摄取目标转换成图像信号&#xff0c;传送给专用的图像处理系统。图像处理系统对这些信号进行各种运算来抽取目标的特征&#xff0c;进而根据判别的结果来控制现场的设备动作。一般来说&…

Plugin ‘mysql_native_password‘ is not loaded`

Plugin ‘mysql_native_password’ is not loaded mysql_native_password介绍1. 使用默认的认证插件2. 修改 my.cnf 或 my.ini 配置文件3. 加载插件&#xff08;如果确实没有加载&#xff09;4. 重新安装或检查 MySQL 版本 遇到错误 ERROR 1524 (HY000): Plugin mysql_nativ…

苍穹外卖-阿里云OSS文件上传

苍穹外卖-阿里云OSS文件上传 一、阿里云OSS简介**获取AccessKey**获取enpoint 二、代码实现1 引入依赖2 定义OSS相关配置2.1 application-dev.yml2.2 application.yml 3 读取OSS配置3.1 AliOssProperties 4 生成OSS工具类对象4.1 AliOssUtil4.2 OssConfiguration2.5 CommonCont…

【工具】前端 js 判断当前日期是否在当前自然周内

【工具】前端 js 判断当前日期是否在当前自然周内 function isCurrentNaturalWeek(targetDate) {const today new Date();const dayOfWeek today.getDay(); // 0&#xff08;周日&#xff09;到6&#xff08;周六&#xff09;// 计算本周一的日期&#xff08;自然周从周一开…

【操作系统】处理机调度

处理机调度 一、调度的概念、层次1.1 三个层次1.2 七状态模型 二、调度算法的评价指标2.1 CPU利用率2.2 系统吞吐率2.3 周转时间2.4 等待时间2.5 响应时间 三、进程调度&#xff08;低级调度&#xff09;的时机3.1 需要进程调度的情况3.2 不能进程调度的情况3.3 闲逛进程 四、进…

SpringBoot 使用 spring.profiles.active 来区分不同环境配置

很多时候&#xff0c;我们项目在开发环境和生产环境的配置是不一样的&#xff0c;例如&#xff0c;数据库配置&#xff0c;在开发的时候&#xff0c;我们一般用测试数据库&#xff0c;而在生产环境&#xff0c;我们要用生产数据库&#xff0c;这时候&#xff0c;我们可以利用 p…

怎么进行mysql的优化?

MySQL 的优化是一个系统性的工作&#xff0c;涉及多个层面&#xff0c;包括查询优化、索引优化、配置优化、架构优化等。以下是一些常见的 MySQL 优化方法&#xff1a; 查询优化 避免全表扫描&#xff1a;确保查询能够使用索引&#xff0c;避免 SELECT *&#xff0c;只选择需要…

谈谈 Node.js 中的模块系统,CommonJS 和 ES Modules 的区别是什么?

Node.js 模块系统&#xff1a;CommonJS 和 ES Modules 核心差异与实战指南 一、模块系统基础概念 **CommonJS (CJS)**​ 是 Node.js 传统模块系统&#xff0c;采用同步加载方式&#xff0c;典型特征&#xff1a; // 导出 module.exports { name: cjs }; // 或 exports.nam…

【HarmonyOS Next】 鸿蒙应用useNormalizedOHMUrl详解

【HarmonyOS Next】 鸿蒙应用useNormalizedOHMUrl详解 一、useNormalizedOHMUrl是什么? useNormalizedOHMUrl指的是是否使用标准化OHMUrl拼接。 在开发过程中&#xff0c;需要根据不同的环境或配置动态生成 URL。例如&#xff0c;在加载一些远程模块或者资源时&#xff0c;…

wav格式的音频压缩,WAV 转 MP3 VBR 体积缩减比为 13.5%、多个 MP3 格式音频合并为一个、文件夹存在则删除重建,不存在则直接建立

&#x1f947; 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 &#x1f389; 声明: 作为全网 AI 领域 干货最多的博主之一&#xff0c;❤️ 不负光阴不负卿 ❤️ 文章目录 问题一&#xff1a;wav格式的音频压缩为哪些格式&#xff0c;网络传输给用户播放…

MFC线程

创建线程 HANDLE m_hThread; m_hThread CreateThread(NULL, 0, save_snapshot, (LPVOID)this, 0, &iThreadId);开启线程循环等待 DWORD WINAPI save_snapshot(LPVOID pVoid) {while (true){//持续循环等待事件到达。接收到事件信号后才进入if。if (::WaitForSingleObjec…

赋能农业数字化转型 雏森科技助力“聚农拼”平台建设

赋能农业数字化转型&#xff0c;雏森科技助力“聚农拼”平台建设 在数字化浪潮席卷各行业的今天&#xff0c;农业领域也在积极探索转型升级之路。中农集团一直以“根植大地&#xff0c;服务三农”为核心&#xff0c;以“乡村振兴&#xff0c;农民增收”为目标&#xff0c;及时…

千峰React:Hooks(上)

什么是Hooks ref引用值 普通变量的改变一般是不好触发函数组件的渲染的&#xff0c;如果想让一般的数据也可以得到状态的保存&#xff0c;可以使用ref import { useState ,useRef} from reactfunction App() {const [count, setCount] useState(0)let num useRef(0)const h…

Ubuntu20.04安装Redis

1.切换到root用户 如果没有切换到root用户的&#xff0c;切换到root用户。 2.使用 apt install redis 安装redis 遇到y/n直接y即可。 redis安装好之后就自动启动起来了&#xff0c;因此我们可以通过netstat -anp | grep redis命令来查看是否安装成功。 6379是Redis的默认端…

鸿蒙-AVPlayer

compileVersion 5.0.2&#xff08;14&#xff09; 音频播放 import media from ohos.multimedia.media; import common from ohos.app.ability.common; import { BusinessError } from ohos.base;Entry Component struct AudioPlayer {private avPlayer: media.AVPlayer | nu…

机器学习数学通关指南——泰勒公式

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 一句话总结 泰勒公式是用多…

游戏引擎学习第124天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾/复习 今天是继续完善和调试多线程的任务队列。之前的几天&#xff0c;我们已经介绍了多线程的一些基础知识&#xff0c;包括如何创建工作队列以及如何在线程中处理任务。今天&#xff0c;重点是解决那些我们之前没有注意到…

在MacOS上打造本地部署的大模型知识库(一)

一、在MacOS上安装Ollama docker run -d -p 3000:8080 --add-hosthost.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main 最后停掉Docker的ollama&#xff0c;就能在webui中加载llama模…