由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.pswp.cn/news/287436.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287436.shtml
英文地址,請注明出處:http://en.pswp.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…