【C#学习笔记】装箱和拆箱

news2024/9/20 10:45:04

在这里插入图片描述

文章目录

  • 装箱和拆箱
    • 性能消耗
    • 装箱
    • 拆箱
  • 比较var,object,dynamic,\<T\>
    • var
    • object
    • \<T\> 泛型
    • dynamic


装箱和拆箱

在讲引用类型object的时候,我们说它是万能的,却没说它万能在哪里。

除了object为每一种变量类型提供了ToString,GetHashCode,Equals,GetType方法之外,object作为所有类型的父类,它可以实现任意变量类型到object的转换

一方面,使用object类型可以显式转换到任意类型,(其中没有发生装箱拆箱):

object arr=new int[10];
int[] ar=(int[])arr;

object arr=new int[10];
int[] ar=arr as int[]; // as强转object类型为int数组

另一方面,我们将一个值类型转化为object(引用类型)的过程称为装箱,而将装箱的object转化回值类型的过程称为拆箱

下例将整型变量 i 进行了装箱并分配给对象 o。

int i = 123;
// The following line boxes i.
object o = i; //隐式装箱

然后,可以将对象 o 取消装箱并分配给整型变量 i:

o = 123;
i = (int)o;  // unboxing

下面是官方示例,展示了如何使用一个object的list来存储不同值类型的数据并对其分别进行操作:

Console.WriteLine(String.Concat("Answer", 42, true));
List<object> mixedList = new List<object>();
mixedList.Add("First Group:");

for (int j = 1; j < 5; j++)
{
    mixedList.Add(j);
}

mixedList.Add("Second Group:");
for (int j = 5; j < 10; j++)
{
    mixedList.Add(j);
}

foreach (var item in mixedList)
{
    Console.WriteLine(item);
}

var sum = 0;
for (var j = 1; j < 5; j++)
{
    sum += (int)mixedList[j] * (int)mixedList[j];
     // 注意在进行数值运算的时候不能用object直接运算,应当拆箱为原类型再计算
}
Console.WriteLine("Sum: " + sum);

// Output:
// Answer42True
// First Group:
// 1
// 2
// 3
// 4
// Second Group:
// 5
// 6
// 7
// 8
// 9
// Sum: 30

性能消耗

相对于简单的赋值而言,装箱和取消装箱过程需要进行大量的计算。 对值类型进行装箱时,必须分配并构造一个新对象。 取消装箱所需的强制转换也需要进行大量的计算,只是程度较轻。

实际上,在编程中应当尽量避免装箱和拆箱,除非真的必须要使用。

如果一个变量被装箱引用后还需要被拆箱引用,倒不如直接赋值一个新的变量,因为对值类型进行装箱时,必须创建一个全新的对象, 这可能比简单的引用赋值用时最多长 20 倍。 取消装箱的过程所需时间可达赋值操作的四倍。

如果一个变量,一个方法需要频繁装箱拆箱,说明本身程序设计就存在问题。例如定义了一个接受任意输入类型的函数,但是所有的输入值类型在方法内都会被强制转化为object类型。就比如上面例子中定义的List<object>,我们每存入一个值就要被装箱一次。实际上定义一个泛型List<T>是更好的选择,当我们需要接收任意值类型变量时,应当使用泛型来代替object对其他类型的装箱。例如下面的例子,显然前者更好:

    public class Stack<T>
    {
        List<T> a = new List<T>();
    }
    public class Stack
    {
        List<object> b = new List<object>();
    }

装箱

装箱用于在垃圾回收堆中存储值类型。 装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。 对值类型装箱会在堆中分配一个对象实例,并将该值复制到新的对象中。

此语句的结果是在堆栈上创建对象引用 o,而在堆上则引用 int 类型的值。 该值是赋给变量 i 的值类型值的一个副本。 以下装箱转换图说明了 i 和 o 这两个变量之间的差异:

在这里插入图片描述
(从上图中可以看到,原本i作为值类型存储在栈上,而object作为引用类型存储在堆上。当我们执行装箱操作的时候,一方面将值类型的装箱类型记录在了堆上,同时将堆上的object的值赋值为了123,并且在栈上同时创建了一个引用o用于引用堆上的object。)

这意味着在装箱的时候,object只是复制了i的值,而非它的地址本身,这也容易理解,因为值类型赋值的时候会重新创建一个地址,引用值类型是不可靠的:

class TestBoxing
{
    static void Main()
    {
        int i = 123;
        // Boxing copies the value of i into object o.
        object o = i;
        // Change the value of i.
        i = 456;
        // The change in i doesn't affect the value stored in o.
        System.Console.WriteLine("The value-type value = {0}", i);
        System.Console.WriteLine("The object-type value = {0}", o);
    }
}
/* Output:
    The value-type value = 456
    The object-type value = 123
*/

拆箱

取消装箱是从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。 取消装箱操作包括:

  • 检查对象实例,以确保它是给定值类型的装箱值。

  • 将该值从实例复制到值类型变量中。
    在这里插入图片描述

从拆箱过程可以看出,实际上我们拆箱的时候,首先判断拆箱项o是否是对object的引用。然后判断拆箱类型是否是object的装箱类型,最后拆箱的值将会在栈中重新创建一个。

此外,拆箱也存在着隐式转换,但拆箱项类型必须相同,例如下面的例子:

float t =(int) o; //拆箱项正确,拆出的int可直接隐式转换为folat
int t =(float) o; //拆箱项错误

根据上述原理,如果想要改变一个已经装箱的object的值,唯一的方法只有先拆箱,再重新装箱。


比较var,object,dynamic,<T>

这四种方法看起来比较类似,都可以接收任意类型,但实际区别很大。

var

var的原理是基于编译器,当我们用var来定义变量类型时,只能用于局部变量,并且是让编译器从初始化表达式推断出变量的类型。

var a = 12;
a.IndexOf("1", 0, 2); //报错,编译器已经推测出a是int类型了,不能使用string的方法

var 的常见用途是用于构造函数调用表达式。当函数中的一些局部变量的赋值类型不明的时候,使用var来接收是安全的。使用var类型应当是最方便最随意的。

object

object虽然可以转化为任意类型,也可以通过装箱接收值类型的转换。优点是我们可以将object类型作为函数的返回类型,也可以在函数的入参中定义object类。但是它的优点也是它的缺点,假设函数里定义了object入参,鬼知道当别人使用函数的时候会传入什么东西进去,情况会变得越来越复杂。要么使用泛型,要么指定参数类型,在函数内部对其装箱。

因此,我们最好只在类型转换的时候使用object。如果想在函数定义一个可变类型,并且也不希望出现装箱拆箱,请使用<T>

<T> 泛型

泛型除了不能定义变量,其他都能定义。可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。还可以对泛型类进行约束以访问特定数据类型的方法。

一个简单的泛型例子就是集合类提供的List<T>。这个东西有多好用就不用讲了。

使用泛型在各种类或方法中获取任意类型。泛型不用装箱拆箱。你可以将泛型理解成替换,在使用的时候将泛型参数替换成具体的类型,这个过程是在编译的时候进行的,使用泛型,编译器依然能够检测出类型错误。

dynamic

dynamic本身也是一个Object。在大多数情况下,dynamic 类型与 object 类型的行为类似。 具体而言,任何非 Null 表达式都可以转换为 dynamic 类型。 dynamic 类型与 object 的不同之处在于,编译器不会对包含类型 dynamic 的表达式的操作进行解析或类型检查。 编译器将有关该操作信息打包在一起,之后这些信息会用于在运行时评估操作。 在此过程中,dynamic 类型的变量会编译为 object 类型的变量。 因此,dynamic 类型只在编译时存在,在运行时则不存在。

优点就是dynamic像大部分脚本语言一样是动态变量,一方面方便某些动态使用,另一方面也可以和脚本语言对接。

但是缺点也很明显,可能有时使用它写的程序想要debug就没那么简单了。同时也别把dynamic作为函数的参数或者返回值,它只会比object带来更麻烦的后果。

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

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

相关文章

收集 301 医院 451 名老年冠心病患者数据,湖北麻城人民医院推出机器学习模型,准确预测患者一年内死亡率

内容一览&#xff1a;据国际糖尿病联盟 (IDF) 统计&#xff0c;2021 年中国糖尿病患者数量占全球 26%。而糖尿病患者血糖长期失控&#xff0c;有极高风险引起冠心病等并发症。近期&#xff0c;湖北省麻城市人民医院研究人员分析比较了多种模型&#xff0c;并用其中表现最优的机…

Scratch 之 两点之间距离的测算

1.前言 在Scratch中&#xff0c;对于坐标系上的两点&#xff0c;我们可以确定通过x坐标或y坐标之差确定两点横坐标或是纵坐标上的距离&#xff0c;那么如何知道两点之间的直线距离呢&#xff1f; 2.勾股定理 对于一个直角三角形&#xff0c;两条直角边的平方和等于斜边的平方&a…

电动自行车上架eBay的UL2849、16CFR1512测试标准

在奥运经济的带动下&#xff0c;今年以来运动自行车消费有较大幅度增长&#xff0c;其中高端消费者对进口自行车需求扩张&#xff0c;上半年竞赛型自行车进口量同比增长49.5%。另外&#xff0c;电助力自行车在国际市场也倍受追捧&#xff0c;国际自行车贸易总额的60%来自中国&a…

记一次ubuntu16误删libc.so.6操作的恢复过程

背景 操作系统&#xff1a;ubuntu16 glibc版本&#xff1a;2.23 修改原因&#xff1a; 经过一系列报错和手工构建之后&#xff0c;vulkansdk成功安装&#xff08;起码运行./vulkansdu成功&#xff09;&#xff0c;在进行./vulkaninfo进行验证时&#xff0c;报错&#xff1a…

SpringCloud-Hystrix服务熔断与降级工作原理源码 | 京东物流技术团队

先附上Hystrix源码图 在微服务架构中&#xff0c;根据业务来拆分成一个个的服务&#xff0c;服务与服务之间可以相互调用&#xff08;RPC&#xff09;&#xff0c;在Spring Cloud可以用RestTemplateRibbon和Feign来调用。为了保证其高可用&#xff0c;单个服务通常会集群部署。…

odoo16 上传/下载 文件接口的实现

突然有个需求说需要编写一个上传pdf 接口 首先需要准备如下 xx.xx模型 module 部分 如下&#xff1a; attachment_count fields.Integer(compute_compute_attachment_count, string附件数量, requiredTrue)def _compute_attachment_count(self):# 附件数量计算attachment_dat…

虹科干货 | DevOps 团队为什么独独青睐 Redis Enterprise ?

虹科干货 | DevOps 团队为什么独独青睐 Redis Enterprise &#xff1f; 快速部署是保障成功的 DevOps 的关键要素。虹科Redis Enterprise 提供了一种快速的数据库。 DevOps 团队面临的挑战 提高应用程序处理速度&#xff0c;赢得商业竞争 许多企业中&#xff0c;DevOps 团队&…

工厂模式:简化对象的创建过程

工厂模式&#xff1a;简化对象的创建过程 介绍 在软件开发中&#xff0c;对象的创建是一个常见的操作。通常情况下&#xff0c;我们可以直接使用 new 关键字来创建对象&#xff0c;但是在某些情况下&#xff0c;对象的创建过程可能会比较复杂&#xff0c;涉及到多个步骤或者依…

为生成式AI提速,亚马逊云科技Amazon EC2 P5满足GPU需求

生成式AI&#xff08;Generative AI&#xff09;已经成为全球范围内的一个重要趋势&#xff0c;得到越来越多企业和研究机构的关注和应用。纽约时间7月26日&#xff0c;亚马逊云科技数据库、数据分析和机器学习全球副总裁Swami Sivasubramanian在亚马逊云科技举办的纽约峰会上更…

React Native获取手机屏幕宽高(Dimensions)

import { Dimensions } from react-nativeconsole.log(Dimensions, Dimensions.get(window)) 参考链接&#xff1a; https://www.reactnative.cn/docs/next/dimensions#%E6%96%B9%E6%B3%95 https://chat.xutongbao.top/

程序员自由创业周记#5:加一上线

程序员自由创业周记#5&#xff1a;加一上线 这是一位程序员进行独立开发创业的记录&#xff0c;将分享创业过程中的所思所想以及收支明细。 充实 如果说程序员独立创业的成功率只有5%&#xff0c;那如果家里有一位3岁多还没上幼儿园的小朋友要照顾&#xff0c;成功的概率至少还…

通俗易懂web3.0

目录 前言一、WEB1.0二、WEB2.0三、WEB3.0区别最后 前言 大家好&#xff0c;我是清风。互联网连接了人与人&#xff0c;在过去的30年中&#xff0c;互联网技术不断进化、演化&#xff0c;向纵深发展&#xff0c;政治、经济、社交、生活、工作已经几乎离不开互联网。我们经历了…

软件测试面试【富途面经分享】

目录 一面面经&#xff08;1h&#xff09; 二面面经 一面面经&#xff08;1h&#xff09; 一、对白盒黑盒灰盒测试的理解 答&#xff1a; 1、黑盒测试就当整个程序是个黑盒子&#xff0c;我们看不到它里面做了什么事情&#xff0c;只能通过输入输出看是否能得到我们所需的来…

使用HTTP隧道时如何应对目标网站的反爬虫监测?

在进行网络抓取时&#xff0c;我们常常会遇到目标网站对反爬虫的监测和封禁。为了规避这些风险&#xff0c;使用代理IP成为一种常见的方法。然而&#xff0c;如何应对目标网站的反爬虫监测&#xff0c;既能保证数据的稳定性&#xff0c;又能确保抓取过程的安全性呢&#xff1f;…

亚马逊关键词的作用有哪些?

亚马逊关键词在平台上扮演着重要的作用&#xff0c;涵盖了消费者、卖家和整个平台的多个方面&#xff1a; 1、消费者的作用&#xff1a; 帮助消费者快速找到所需商品&#xff1a;通过输入关键词&#xff0c;消费者可以迅速找到感兴趣的商品&#xff0c;节省时间和精力。 支持…

【Linux】运行程序前加上strace,可以追踪到函数库调用过程

rootubuntu:/home/peng/test# gcc 123.c -o run rootubuntu:/home/peng/test# strace ./run 如执行结果可知&#xff1a; 我们的程序虽然只有一个printf函数&#xff0c;但是在执行过程中&#xff0c;我们前后调用了execve、access、open、fstat、mmap、brk、write等系统调用。…

01_二值图、灰度图、彩色图

01_二值图、灰度图、彩色图 1. 二值图2. 灰度图3. 彩色图 1. 二值图 二值图像&#xff08;黑白图像&#xff09;&#xff1a;每个像素点只有两种可能&#xff0c;0和1&#xff0c;0代表黑色&#xff0c;1代表白色。数据类型通常为1个二进制位。 得出来的图像 2. 灰度图 单…

ad+硬件每日学习十个知识点(22)23.8.2(LDO datasheet手册解读)

文章目录 1.LDO的概述、features2.LDO的绝对参数&#xff08;功率升温和结温&#xff09;3.LDO的引脚功能4.LDO的电气特性5.LDO的典型电路&#xff08;电容不能真用1uF&#xff0c;虽然按比例取输出值&#xff0c;但是R2的取值要考虑释放电流&#xff09;6.LDO的开关速度和线性…

PaperEdge 文档图像矫正

效果 地址&#xff1a; https://github.com/cvlab-stonybrook/PaperEdge

leaflet-uniapp 缩放地图的同时 显示当前缩放层级

记录实现过程&#xff1a; 需求为移动端用户在使用地图时&#xff0c;缩放地图的同时&#xff0c;可以获知地图此时缩放的级别。 效果图如下&#xff1a;此时缩放地图级别为13 map.on() 有对应的诸多行为 查看官网即可&#xff0c;这里根据需要为--zoomstart zoom zoomend 代…