網站首頁 編程語言 正文
前言
前幾天在技術群里看到有同學在討論關于dynamic是否會存在裝箱拆箱的問題,我當時第一想法是"會"。至于為啥會有很多人有這種疑問,主要是因為覺得dynamic
可能是因為有點特殊,因為它被稱為動態類型
,可能是因為這里的動態對大家造成的誤解,認為這里的動態可以推斷出具體的類型,所以可以避免裝箱拆箱。但是事實并不是這樣,今天就一起就這個問題雖然討論一下。
裝箱拆箱
首先咱們先來看下何為裝箱拆箱,這個可以在微軟官方文檔中Boxing and Unboxing文檔中看到答案,咱們就簡單的摘要一下相關的描述
裝箱是將值類型轉換為類型對象或此值類型實現的任何接口類型的過程。當公共語言運行時 (CLR) 將值類型裝箱時,它會將值包裝在 System.Object 實例中并將其存儲在托管堆上。拆箱從對象中提取值類型。拳擊是隱含的;拆箱是明確的。裝箱和拆箱的概念是 C# 類型系統統一視圖的基礎,其中任何類型的值都可以視為對象。
翻譯起來會比較抽象,理解起來就是利用裝箱和拆箱功能,可通過允許值類型的任何值與Object 類型的值相互轉換,將值類型與引用類型鏈接起來。也就是值類型和引用類型相互轉換的一做橋梁,但是問題也很明顯那就是實例會存在在堆棧之前相互copy的問題,會存在一定的性能問題,所以這也一直是一個詬病。
雖然說是這樣但是也沒必要一直扣死角,畢竟很多時候程序還沒有糾結到這種程度,因為任何語言存在的各種方法中或者操作中都會有一定這種問題,所以本質不是語言存在各種問題,而是在什么場景如何使用的問題。比如避免出現裝箱和拆箱的辦法也就是入概念所說的,那就是避免值類型和和引用類型之間相互轉換,但是很多時候還是避免不了的,所以也不必糾結。
探究本質
上面講解了關于裝箱拆箱
的概念,接下來咱們就來定義一段代碼看看效果,為了方便對比咱們直接對比著看一下
dynamic num = 123; dynamic str = "a string";
想要看清本質還是要反編譯一下生成的結果看一下的,這里我們可以借助ILSpy
或dnSpy
來看下,首先看一下反編譯回來的效果
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.Int32 IL_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: nop IL_0015: nop IL_0016: nop IL_0017: nop IL_0018: nop IL_0019: nop IL_001a: nop IL_001b: nop // } IL_001c: nop IL_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上運行的動態語言,并為靜態類型語言添加動態特征。
匿名類型
總會有人拿dynamic
和var
進行比較,但是本質上來說,這兩者描述的不是一個層面的東西。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
相信這里就可以看出來了dynamic
和var
確實也不是一個層面的東西。var是隱式類型是語法糖為了簡化編程體驗用的,dynamic則是動態語言運行時技術,編譯時轉換成object類型,因為在c#上一切都是object,然后再運行時進行具體的操作。
總結
本篇文章主要是在技術群里看到有同學在討論關于dynamic是否會裝箱引發的思考,相對來說講解的比較基礎也比較簡單。想對一個東西理解的更透徹,就要一步一步的了解它到底是什么,這樣的話就可以更好的理解和思考。也印證了那句話,你不會用或者用是因為你對它不夠了解,當你對它有足夠理解的時候,操作起來也就會游刃有余。
原文鏈接:https://www.cnblogs.com/wucy/p/16281540.html
相關推薦
- 2022-06-13 Python+Matplotlib繪制雙y軸圖像的示例代碼_python
- 2022-05-15 實例詳解Python的進程,線程和協程_python
- 2022-03-03 GitHub 私人private倉庫添加成員(協作者Collaborators)
- 2022-03-26 正則表達式詳析+常用示例_正則表達式
- 2021-12-06 Gin框架之參數綁定的實現_Golang
- 2023-07-15 oracle查看死鎖以及處理死鎖
- 2022-11-02 Linux命令sed(流編輯器)的用法詳解_linux shell
- 2022-04-11 springboot上傳文件到Nginx代理的FTP文件服務器
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支