<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前幾天在技術群裡看到有同學在討論關於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是否會裝箱引發的思考,相對來說講解的比較基礎也比較簡單。想對一個東西理解的更透徹,就要一步一步的瞭解它到底是什麼,這樣的話就可以更好的理解和思考。也印證了那句話,你不會用或者用是因為你對它不夠了解,當你對它有足夠理解的時候,操作起來也就會遊刃有餘。
到此這篇關於關於C# dynamic裝箱引發的思考的文章就介紹到這了,更多相關C# dynamic裝箱內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45