.NET C# 装箱与拆箱

.NET C# 装箱与拆箱

目录

  • .NET C# 装箱与拆箱
    • 1 装箱 (Boxing)
      • 1.1 过程:
      • 1.2 示例:
    • 2 拆箱 (Unboxing)
      • 2.1 过程:
      • 2.2 示例:
    • 3 性能影响
    • 4 性能优化
      • 4.1 使用泛型集合
        • 示例:
      • 4.2 使用`Nullable<T>`
        • 示例:
      • 4.3 避免使用非泛型集合
        • 示例:
      • 4.4 避免在接口类型上操作值类型
      • 4.5 使用结构体实现接口时,小心装箱
        • 示例:
      • 4.6 使用`readonly struct`优化性能
        • 示例:
      • 4.7 使用`Span<T>`和`Memory<T>`
        • 示例:
      • 4.8 使用内联方法(`[MethodImpl(MethodImplOptions.AggressiveInlining)]`)
        • 示例:

在C#中,装箱和拆箱是将值类型转换为引用类型及其逆过程的操作。理解装箱和拆箱对于性能优化和正确使用类型转换非常重要。下面详细介绍这两个过程。

1 装箱 (Boxing)

装箱是将值类型转换为引用类型的过程。值类型存储在栈中,而引用类型存储在堆中。装箱过程会将值类型的值拷贝到堆中,并创建一个引用对象。

1.1 过程:

  1. 在堆中分配内存以存储值类型数据和类型信息。
  2. 将值类型数据拷贝到新分配的内存中。
  3. 返回对该内存的引用。

1.2 示例:

int value = 123;          // 值类型
object obj = value;       // 装箱,将值类型转换为引用类型

在这个示例中,value是一个整数,属于值类型。当我们将它赋值给obj时,发生了装箱操作,obj现在是对堆中整数值123的引用。

2 拆箱 (Unboxing)

拆箱是将引用类型转换回值类型的过程。拆箱时必须确保引用类型实际上是被装箱的值类型,否则会抛出InvalidCastException

2.1 过程:

  1. 检查引用是否指向已装箱的值类型数据。
  2. 从堆中提取值类型数据并复制到栈上的值类型变量中。

2.2 示例:

object obj = 123;         // 装箱
int value = (int)obj;     // 拆箱

在这个示例中,obj包含装箱的整数值123。当我们将obj拆箱为整数时,需要进行显式类型转换,即(int)obj。这会将引用类型转换回值类型,并将数据复制回栈中的value

3 性能影响

  • 装箱和拆箱是开销较大的操作,因为它们涉及堆内存的分配和释放以及数据的复制。
  • 尽量避免频繁的装箱和拆箱操作。例如,使用List<int>而不是ArrayList来存储整数,这样可以避免装箱和拆箱操作,因为List<int>是类型安全的。

4 性能优化

一些策略和技巧可以帮助减少或避免装箱和拆箱操作。以下是一些详细的方法:

4.1 使用泛型集合

泛型集合类如List<T>Dictionary<TKey, TValue>Queue<T>Stack<T>等,都可以避免值类型的装箱和拆箱。泛型允许在编译时确定类型,从而直接在值类型上操作,而不需要转换为引用类型。

示例:
// 使用泛型集合避免装箱和拆箱
List<int> numbers = new List<int>();
numbers.Add(42);          // 不会发生装箱
int number = numbers[0];  // 不会发生拆箱

4.2 使用Nullable<T>

Nullable<T>结构(也可以使用T?语法)允许值类型可以为空,而不需要装箱。

示例:
int? nullableInt = 5;     // 不会发生装箱
nullableInt = null;       // 不会发生装箱if (nullableInt.HasValue)
{int value = nullableInt.Value;  // 不会发生拆箱
}

4.3 避免使用非泛型集合

尽量避免使用非泛型集合类如ArrayListHashtableQueueStack等,因为它们会导致值类型的装箱和拆箱。可以使用对应的泛型版本。

示例:
// 避免使用ArrayList,因为它会导致装箱和拆箱
ArrayList arrayList = new ArrayList();
arrayList.Add(42);        // 装箱
int value = (int)arrayList[0]; // 拆箱// 使用List<int>来避免装箱和拆箱
List<int> list = new List<int>();
list.Add(42);             // 不会发生装箱
int value2 = list[0];     // 不会发生拆箱

4.4 避免在接口类型上操作值类型

当值类型通过接口进行操作时,会发生装箱。例如:

int x = 10;
IComparable comparable = x;  // 装箱
int result = comparable.CompareTo(5); // 拆箱

避免这种情况的方法是直接在值类型上操作,而不是通过接口:

int x = 10;
int result = x.CompareTo(5);  // 不会发生装箱和拆箱

4.5 使用结构体实现接口时,小心装箱

如果结构体实现了接口,并且接口方法在结构体实例上被调用时,会发生装箱。可以通过显示实现接口或者直接调用结构体的方法来避免装箱。

示例:
struct MyStruct : IComparable<MyStruct>
{public int CompareTo(MyStruct other){// 实现接口方法return 0;}
}MyStruct a = new MyStruct();
MyStruct b = new MyStruct();
int result = a.CompareTo(b);  // 不会发生装箱IComparable<MyStruct> comparable = a;
result = comparable.CompareTo(b); // 装箱

4.6 使用readonly struct优化性能

在一些场景下,使用readonly struct可以提高性能,因为它们是不可变的,编译器可以进行更多优化,并且在某些情况下可以减少装箱。

示例:
readonly struct ImmutablePoint
{public int X { get; }public int Y { get; }public ImmutablePoint(int x, int y){X = x;Y = y;}
}

4.7 使用Span<T>Memory<T>

在需要处理大块内存时,使用Span<T>Memory<T>可以避免装箱和拆箱,提供更高效的内存操作。

示例:
Span<int> span = stackalloc int[100]; // 不会发生装箱
for (int i = 0; i < span.Length; i++)
{span[i] = i; // 直接操作,不会发生装箱和拆箱
}

4.8 使用内联方法([MethodImpl(MethodImplOptions.AggressiveInlining)]

在性能关键的代码中,内联方法可以减少函数调用开销,并在某些情况下避免装箱和拆箱。

示例:
using System.Runtime.CompilerServices;struct MyStruct
{public int Value;[MethodImpl(MethodImplOptions.AggressiveInlining)]public void SetValue(int value){Value = value;}
}

通过综合使用这些方法,可以有效减少或避免装箱和拆箱操作,提高C#程序的性能。

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

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

相关文章

速通数学建模 —— 查找数据

目录 百度搜索技巧 完全匹配搜索&#xff1a;查询词的外边加上双引号“ ” 标题必含关键词&#xff1a;查询词前加上intitle: 搜索文档&#xff1a;空格再输入filetype:文件格式 去掉不想要的&#xff1a;查询词后面加空格后加减号与关键字 知网查文献 先看知网的硕博士…

[AIGC] 深度优先搜索(DFS)详解及其在LeetCode问题中的应用

深度优先搜索&#xff08;Depth-First-Search&#xff0c;简称DFS&#xff09;是一种用于遍历或搜索树或图的算法&#xff0c;其思想是从一个顶点 V0 开始&#xff0c;沿着一条路一直走到底&#xff0c;如果发现不能到达目标解&#xff0c;就退回到上一步的状态&#xff0c;转向…

经典游戏案例:愤怒的小鸟

学习目标&#xff1a;愤怒的小鸟核心玩法 游戏画面 项目结构目录 部分核心代码 using System.Collections; using System.Collections.Generic; using birds; using utils; using UnityEngine;public class GameManager : MonoBehaviour {public static GameManager sInstanc…

【C++】优先队列的使用及模拟实现

&#x1f497;个人主页&#x1f497; ⭐个人专栏——C学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读 一、什么是优先队列 二、优先队列的使用 1. 优先队列的构造 2. 优先队列的基本操作 3. 使用示例 三、优先队列模拟实…

【硬件开发】共模电感

为什么电源无论直流还是交流的输入端都需要一个共模电感 图中L1就是共模电感&#xff0c;长下面这个样子&#xff0c;两侧的匝数&#xff0c;线径和材料都是一模一样的 共模电感的作用是为了抑制共模信号 抑制共模信号工作原理 http://【共模电感是如何抑制共模信号的】https…

【免费】中国电子学会2024年03月份青少年软件编程Python等级考试试卷一级真题(含答案)

2024-03 Python一级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 下列哪个命令&#xff0c;可以将2024转换成2024 呢&#xff1f;&#xff08; A&#xff09;(2分) A.str(2024) B.int(2024) C.fl…

细说AGV的12种导航方式和原理

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 这十二种导航方式各自具有不同的特点和应用场景&#xff0c;下面我将逐一进行简要介绍&#xff1a; 磁钉导航&#xff1a; 原理&#xf…

Python学习笔记17:进阶篇(六)代码测试

代码测试 代码测试是软件开发过程中的关键环节&#xff0c;旨在确保代码质量、功能正确性以及性能符合预期。 在开发过程中&#xff0c;进行代码测试有很多好处&#xff1a; 提高软件质量&#xff1a;通过发现并修复错误&#xff0c;测试有助于提升软件的功能性、可靠性和稳…

LSTM架构的演进:LSTM、xLSTM、LSTM+Transformer

文章目录 1. LSTM2. xLSTM2.1 理论介绍2.2 代码实现 3. LSTMTransformer 1. LSTM 传统的 LSTM (长短期记忆网络) 的计算公式涉及几个关键部分&#xff1a;输入门、遗忘门、输出门和单元状态。 2. xLSTM xLSTM之所以称之为xLSTM就是因为它将LSTM扩展为多个LSTM的变体&#xff…

【LLVM】‘ffast-math’ and ‘ffp-contract’

最近看到一个issue&#xff0c;修改的核心代码部分并不多&#xff0c;可以参考此处的介绍以及此处的issue。 看起来关键就是判断-ffp-contract会将contract的值设为最后一个此选项的值&#xff0c;否则的话&#xff0c;如果只指定了-ffast-math但是没有通过-ffp-contract设置值…

fffdddd

library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all;entity GJL isport(clk, reset: in std_logic;btn_green, btn_red: in std_logic; -- 新增控制按键r1, r2, y1, y2, g1, g2: out std_logic;ledag: out std_logic_…

网络编程--网络理论基础(二)

这里写目录标题 网络通信流程mac地址、ip地址arp协议交换机路由器简介子网划分网关 路由总结 为什么ip相同的主机在与同一个互联网服务通信时不冲突公网ip对于同一个路由器下的不同设备&#xff0c;虽然ip不冲突&#xff0c;但是因为都是由路由器的公网ip转发通信&#xff0c;接…

在Java中使用Apache Kafka进行消息队列处理

在Java中使用Apache Kafka进行消息队列处理 消息队列(Message Queue)是分布式系统中用于异步通信的关键组件,广泛应用于解耦生产者和消费者、平滑流量突增、提高系统弹性等场景。Apache Kafka作为一个高吞吐量、分布式的消息队列系统,已经成为许多企业的首选。本文将介绍如…

Linux 进程管理指令

Linux 进程管理是系统管理的重要部分&#xff0c;通过各种工具和命令&#xff0c;你可以查看、控制、调试和管理进程。以下是一些常用的 Linux 进程管理命令和工具。 查看进程 1. ps ps 命令用于列出当前系统的进程。 查看当前用户的所有进程&#xff1a; ps -u $USER查看…

Python statistics 模块

Python 的 statistics 模块提供了一组用于执行各种统计计算的函数&#xff0c;包括平均值、中位数、标准差、方差以及其他统计量。让我来简单介绍一下。 首先&#xff0c;你可以使用以下方式导入 statistics 模块&#xff1a; python import statistics 接下来&#xff0c;…

主流中间件--Redis

NOSQL 什么是NOSQL NoSQL(NoSQL Not Only SQL )&#xff0c;意即“不仅仅是SQL”&#xff0c;它泛指非关系型的数据库。 关系型数据库&#xff1a;以关系(由行和列组成的二维表)模型建模的数据库。简单理解&#xff1a;有表的就是关系型数据库。 NOSQL分类 Redis 什么是Redi…

内容安全复习 7 - 对抗攻击与防御

文章目录 概述攻击对抗性攻击的目的攻击的损失函数如何攻击FGSM黑盒与白盒真实世界的攻击 防御被动防御主动防御 概述 动机 &#xff08;1&#xff09;不仅要在实验室中部署机器学习分类器&#xff0c;也要在现实世界中部署&#xff1b;实际应用 &#xff08;2&#xff09;分类…

shell jq教程

1. jq 简介 jq 是一款命令行下处理JSON数据的工具。其可以接受标准输入&#xff0c;命令管道或者文件中的JSON数据&#xff0c;经过一系列的过滤器(filters)和表达式的转后形成我们需要的数据结构并将结果输出到标准输出中。jq的这种特性使我们可以很容易地在Shell脚本中调用它…

LeetCode 23. 合并 K 个升序链表

更多题解尽在 https://sugar.matrixlab.dev/algorithm 每日更新。 组队打卡&#xff0c;更多解法等你一起来参与哦&#xff01; LeetCode 23. 合并 K 个升序链表&#xff0c;难度困难。 优先队列&#xff08;小顶堆&#xff09; 解题思路&#xff1a;拿到题首先想到以下几个方…

【数据结构】线性表之《栈》超详细实现

栈 一.栈的概念及结构二.顺序栈与链栈1.顺序栈2.链栈1.单链表栈2.双链表栈 三.顺序栈的实现1.栈的初始化2.检查栈的容量3.入栈4.出栈5.获取栈顶元素6.栈的大小7.栈的判空8.栈的清空9.栈的销毁 四.模块化源代码1.Stack.h2.Stack.c3.test.c 一.栈的概念及结构 栈&#xff1a;一种…