由c# dynamic是否装箱引发的思考

前言

    前几天在技术群里看到有同学在讨论关于dynamic是否会存在装箱拆箱的问题,我当时第一想法是"会"。至于为啥会有很多人有这种疑问,主要是因为觉得dynamic可能是因为有点特殊,因为它被称为动态类型,可能是因为这里的动态对大家造成的误解,认为这里的动态可以推断出具体的类型,所以可以避免装箱拆箱。但是事实并不是这样,今天就一起就这个问题讨论一下。

装箱拆箱

首先咱们先来看下何为装箱拆箱,这个可以在微软官方文档中Boxing and Unboxing文档中看到答案,咱们就简单的摘要一下相关的描述

装箱是将值类型转换为类型对象或此值类型实现的任何接口类型的过程。当公共语言运行时 (CLR) 将值类型装箱时,它会将值包装在 System.Object 实例中并将其存储在托管堆上。拆箱从对象中提取值类型。拳击是隐含的;拆箱是明确的。装箱和拆箱的概念是 C# 类型系统统一视图的基础,其中任何类型的值都可以视为对象。

翻译起来会比较抽象,理解起来就是利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换,将值类型与引用类型链接起来。也就是值类型和引用类型相互转换的一座桥梁,但是问题也很明显那就是实例会存在在堆栈之前相互copy的问题,会存在一定的性能问题,所以这也一直是一个诟病。

虽然说是这样但是也没必要一直扣死角,毕竟很多时候程序还没有纠结到这种程度,因为任何语言存在的各种方法中或者操作中都会有一定这种问题,所以本质不是语言存在各种问题,而是在什么场景如何使用的问题。比如避免出现装箱和拆箱的办法也就是如概念所说的,那就是避免值类型和和引用类型之间相互转换,但是很多时候还是避免不了的,所以也不必纠结。

探究本质

上面讲解了关于装箱拆箱的概念,接下来咱们就来定义一段代码看看效果,为了方便对比咱们直接对比着看一下

dynamic num = 123;
dynamic str = "a string";

想要看清本质还是要反编译一下生成的结果看一下的,这里我们可以借助ILSpydnSpy来看下,首先看一下反编译回来的效果

private static void <Main>$(string[] args)
{object num = 123;object str = "a string";Console.ReadKey();
}

因为我是使用的是.net6的顶级声明方式所以会生成<Main>$方法。不过从反编译的结果就可以看出来dynamic的本质是object,如果还有点怀疑的话可以直接查看生成的IL代码,还是使用ILSpy工具

.method private hidebysig static void '<Main>$' (string[] args) cil managed 
{// Method begins at RVA 0x2094// Header size: 12// Code size: 30 (0x1e).maxstack 1.entrypoint.locals init (// 这里可以看出声明的num和str变量都是object类型的[0] object num,[1] object str)// object obj = 123;IL_0000: ldc.i4.s 123// 这里的box说明存在装箱操作IL_0002: box [System.Runtime]System.Int32IL_0007: stloc.0// object obj2 = "a string";IL_0008: ldstr "a string"IL_000d: stloc.1// Console.ReadKey();IL_000e: call valuetype [System.Console]System.ConsoleKeyInfo [System.Console]System.Console::ReadKey()IL_0013: pop// (no C# code)IL_0014: nopIL_0015: nopIL_0016: nopIL_0017: nopIL_0018: nopIL_0019: nopIL_001a: nopIL_001b: nop// }IL_001c: nopIL_001d: ret
} // end of method Program::'<Main>$'

通过这里可以看出dynamic的本质确实是object,既然是object那就可以证实确实是存在装箱操作。这个其实在微软官方文档Using type dynamic上有说明,大致描述是这样的

dynamic类型是一种静态类型,但类型为dynamic的对象会跳过静态类型检查。大多数情况下,该对象就像具有类型object一样。在编译时,将假定类型化为dynamic的元素支持任何操作。因此,不必考虑对象是从 COM API、从动态语言(例如 IronPython)、从 HTML 文档对象模型 (DOM)、从反射还是从程序中的其他位置获取自己的值。但是,如果代码无效,则在运行时会捕获到错误。

从这里可以看出dynamic表现出来的就是object,只是dynamic会跳过静态类型检查,所以编译的时候不会报错,有错误的话会在运行的时候报错,也就是我们说的是在运行时确定具体操作。这涉及到动态语言运行时,动态语言运行时(DLR)是一种运行时环境,可以将一组动态语言服务添加到公共语言运行时(CLR)。使用DLR可以轻松开发在.NET上运行的动态语言,并为静态类型语言添加动态特征。

匿名类型

总会有人拿dynamicvar进行比较,但是本质上来说,这两者描述的不是一个层面的东西。var叫隐式类型,本质是一种语法糖,也就是说在编译的时候就可以确定类型的具体类型,也就是说var本质是提供了一种更简单的编程体验,不会影响变量本身的行为。这也就解释了为啥同一个var变量多次赋值不能赋不同类型的值,比如以下操作编译器会直接报错

var num = 123;
num = "123"; //报错

如果你是用的集成开发环境的话其实很容易发现,把鼠标放到var类型上就会显示变量对应的真实类型。或者可以直接通过ILSpy看看反编译结果,比如声明了var num = 123编译完成之后就是

private static void <Main>$(string[] args)
{int num = 123;Console.ReadKey();
}

请注意这里并不是object而是转换成了具体的类型因为123就是int类型的,严谨一点看一下IL代码

.maxstack 1
.entrypoint
//声明的int32
.locals init ([0] int32 num
)
// int num = 123;
IL_0000: ldc.i4.s 123
IL_0002: stloc.0

相信这里就可以看出来了dynamicvar确实也不是一个层面的东西。var是隐式类型是语法糖为了简化编程体验用的,dynamic则是动态语言运行时技术,编译时转换成object类型,因为在c#上一切都是object,然后再运行时进行具体的操作。

总结

    本篇文章主要是在技术群里看到有同学在讨论关于dynamic是否会装箱引发的思考,相对来说讲解的比较基础也比较简单。想对一个东西理解的更透彻,就要一步一步的了解它到底是什么,这样的话就可以更好的理解和思考。也印证了那句话,你不会用或者用是因为你对它不够了解,当你对它有足够理解的时候,操作起来也就会游刃有余。

引用链接

[1] Boxing and Unboxing: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing
[2] Using type dynamic: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic

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

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

相关文章

【看动漫学编程】程序员在异世界生个娃 第3篇:搞不好我就是个王者

前言 作者文笔比较水&#xff0c;还请见谅。 以下内容还将使用视频动态漫画表现&#xff0c;剪辑完将会贴出链接。 小说剧情为剧情需要&#xff0c;过渡到知识点&#xff0c;部分篇幅可能没有技术知识点还望谅解。 由于没有经费支持&#xff0c;所以画出来的东西是我自己用代码…

PHP会话控制考察点

为什么要使用会话控制技术 HTTP协议是无状态的&#xff0c;也就是说HTTP没有一个内建的机制来维护两个事务之间的状态。当一个用户完成一个请求发起第二个请求的时候&#xff0c;服务器无法知道这次请求是来自于上一次的客户。而用户登录、购物车等&#xff0c;这些是需要服务器…

数据库SQL语句学习笔记(6)-使用函数处理数据

1.SQL也可以用函数来处理数据&#xff0c;函数一般是在数据上执行的&#xff0c;为数据的转换和处理提供了方便。但是每一个数据库管理系统&#xff08;DBMS&#xff09;都有特定的函数&#xff0c;事实上&#xff0c;只有少数几个函数被所有的DBMS等同地支持。例如&#xff0c…

java3n 1_1005 继续(3n+1)猜想(JAVA)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递推过程中遇到的每一个数。例如对 n3 进行验证的时候&#xff0c;我们需要计算 3、5、8、4、2、1&…

【遥感物候】Matlab求解一元六次多项式,计算植被生长季始期

一元六次多项式能很好的逼近滤波后的曲线,与二次多项式相比,在拟合植被整个生长季曲线方面有更好的优势,该方法常用来描述北方温带和高纬度地区时序NDVI生长季模式。因此,本文使用一元六次多项式来拟合植被整个生长季曲线,效果很好。那么拟合后,这样解方程呢求生长季参数…

Android之给控件添加水纹波效果

1 问题 给控件添加水纹波效果&#xff0c;点击起来像点中了&#xff0c;不然效果太粗糙了&#xff0c;没反应。 2 实现 给控件添加如下属性 android:background"?android:attr/selectableItemBackground"波纹有边界 android:background"?android:attr/sele…

《看聊天记录都学不会C语言?太菜了吧》(1)我在大佬群里问基础问题没人理?

若是大一学子或者是真心想学习的小伙伴可以私聊我&#xff0c;若你是真心学习可以送你书籍&#xff0c;指导你学习&#xff0c;给予你目标方向的学习路线&#xff0c;无套路&#xff0c;博客为证。 本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖了新手…

个人博客作业_week2

1. 是否需要有代码规范 1.这些规范都是官僚制度下产生的浪费大家的编程时间、影响人们开发效率&#xff0c;浪费时间的东西。 我不同意这个论点。 有句俗语’无规矩不成方圆‘&#xff0c;这亘古传承的至理同样适用于写代码。制定代码撰写规范并不是 迫于压力完成上级的任务&am…

最全面透彻的RabbitMQ指南

概念RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff08;亦称面向消息的中间件&#xff09;。RabbitMQ服务器是用Erlang语言编写的&#xff0c;而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯…

TensorFlow中RNN实现的正确打开方式

上周写的文章《完全图解RNN、RNN变体、Seq2Seq、Attention机制》介绍了一下RNN的几种结构&#xff0c;今天就来聊一聊如何在TensorFlow中实现这些结构&#xff0c;这篇文章的主要内容为&#xff1a; 一个完整的、循序渐进的学习TensorFlow中RNN实现的方法。这个学习路径的曲线较…

【遥感物候】Hants NDVI时间序列谐波分析法数据重构,植被生长季曲线效果可佳(附Hants软件下载)

NDVI时间序列谐波分析法(Harmonic Analysis of NDVI Time-Series)(简称Hants )对时间序列数据进行平滑。该方法是一种新的物候分析方法,可用于定量化的监测植被动态变化。其核心算法是傅里叶变换和最小二乘法拟合, 即把时间波谱数据分解成许多不同频率的正弦曲线和余弦曲线,…

Android之在Java socket作为服务器里面返回数据头部怎么写入浏览器需要下载文件的文件名

1 问题 Android app里面写了一个Java socket的简单服务器,在浏览器里面输入相应的IP和端口访问服务器下载文件,Java socket怎么写返回数据的头部信息,浏览器才知道需要下载文件的名字呢? 2 关于Content-Disposition 在常规的HTTP应答中,Content-Disposition 响应头指示回…

java中hasnext的作用_java中Scanner的hasNext()的疑问

第一个问题&#xff0c;两段代码的区别在于阻塞的位置不同&#xff0c;加上一行输出代码就可以很明显地看到差别。Test.javaimport java.util.Scanner;public class Test {public static void main(String[] args) {Scanner s new Scanner(System.in);while(s.hasNext()){Syst…

《看聊天记录都学不会C语言?太菜了吧》(2)我说编程很容易你们不服?

若是大一学子或者是真心想学习刚入门的小伙伴可以私聊我&#xff0c;若你是真心学习可以送你书籍&#xff0c;指导你学习&#xff0c;给予你目标方向的学习路线&#xff0c;无套路&#xff0c;博客为证。 本系列文章将会以通俗易懂的对话方式进行教学&#xff0c;对话中将涵盖…

ABAP的自学之路 ,初步认识ABAP 一

由于工作的关系&#xff0c;最近需要对SAP系统进行二次开发&#xff0c;于是开始学习ABAP。鉴于网上对于ABAP的资料少之又少&#xff0c;所以自己整理一些资料。 第一章 ABAP 开发环境和总体介绍1.1 ABAP 开发环境ABAP 开发的三种环境&#xff1a;&#xff08;1&#xff09;SAP…

LCD1602,4位数据总线液晶屏时钟,STC12C5A60S2的10位ADC功能程序

/* 程序名&#xff1a;    LCD1602&#xff0c;4位数据总线液晶屏时钟&#xff0c;STC12C5A60S2的10位ADC功能程序 编写时间&#xff1a;  2015年10月4日 硬件支持&#xff1a;  LCD1602液晶屏 STC12C5A60S2 外部12MHZ晶振 接线定义&#xff1a; DB7 --> P1^7DB6…

WPF|黑暗模式的钱包支付仪表盘界面设计

收集下大家的意见&#xff0c;是否需要在文中贴上源码&#xff08;文末会给出源码链接&#xff09;&#xff0c;请大家踊跃留言。阅读目录效果展示准备简单说明 源码结尾&#xff08;视频及源码仓库&#xff09;1. 效果展示欣赏效果&#xff1a;2. 准备创建一个WPF工程&#x…

量子计算机的现状和趋势

量子计算机概述 计算机是一种新型的运算 它具有具有强大的并行处理数据的能力&#xff0c;可解决现有计算机难以运算的数学问题。因此&#xff0c;它成为世界各国战略竞争的焦点。 量子计算机的优势 量子计算机与现有的电子计算机以及正在研究的光计算机&#xff0c;生物计算机…

【空间数据库】Windows操作系统PostgreSQL+PostGIS环境搭建图文安装教程

PostgreSQL是一种特性非常齐全的自由软件的对象-关系型数据库管理系统(ORDBMS),PostgreSQL支持大部分的SQL标准并且提供了很多其他现代特性,如复杂查询、外键、触发器、视图、事务完整性、多版本并发控制等。同样,PostgreSQL也可以用许多方法扩展,例如通过增加新的数据类…

Android之gravity=“center_vertical“和layout_gravity=“center“的效果

1、两控件分别加上2个下面的属性 gravity="center_vertical" android:layout_gravity="center" 代码如下 <LinearLayoutandroid:id="@+id/ll_no_love"android:layout_width="match_parent"android:layout_height="match…