C#裏的var和dynamic區別到底是什麼,你真的搞懂了嘛

前言

這個var和dynamic都是不確定的初始化類型,但是這兩個本質上的不同。不同在哪兒呢?var編譯階段確定類型,dynamic運行時階段確定類型。這種說法對不對呢?本篇看下,文章原文地址:在這裏

概括

以下詳細敘述下這兩個(var,dynamic)上下文關鍵字的不同點。
1.例子

static void Main(string[] args)
{
   var a = 0x10;
   dynamic b = 0x10;
}

var其實在你設置它的變量a的值的那一刻起,它的類型就確定了。這點你可以在VS裏,在var上面查看定義,就可以看到例子裏面a的類型就是Int32。如果你把變量a賦值爲字符串類型,那麼它變量a的類型就是string。嚴格來說還沒到編譯階段,在編譯器VS裏面就被識別了類型。
而dynamic則不同,它類似於public,static。無法查看其實際類型,但是這裏注意了dynamic和var同稱之爲:上下文關鍵字(官方說法是在代碼中提供特殊含義)。也就是說它們兩個在C#裏面嚴格來說都是關鍵字。只不過運作模式不同而已。

2.IL Code

.method private hidebysig static void  Main(string[] args) cil managed
{
  .locals init (int32 V_0,
           object V_1)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   16
  IL_0003:  stloc.0
  IL_0004:  ldc.i4.s   16
  IL_0006:  box        [System.Runtime]System.Int32
  IL_000b:  stloc.1
  IL_000c:  ret
} // end of method Program::Main

在IL裏面,var的操作模式是:將0x10(十進制的16)推送到堆上,然後從堆裏面取出來賦值給a。dynamic的操作模式是:將0x10推送到堆上,然後從堆上取出來作爲參數傳遞給box函數。這裏可以看到很明顯的不同。當然IL依然遠遠不夠。所以下面我們上JIT。

3.ASM Code

var a=0x10
00007FF9FC1A76DC  mov         dword ptr [rbp+3Ch],10h  

dynamic b=0x10
00007FF9FC1A76E3  mov         rcx,7FF9FC10E8D0h  
00007FF9FC1A76ED  call        CORINFO_HELP_NEWSFAST (07FFA5BCA0000h)  
00007FF9FC1A76F2  mov         qword ptr [rbp+28h],rax  
00007FF9FC1A76F6  mov         rax,qword ptr [rbp+28h]  
00007FF9FC1A76FA  mov         dword ptr [rax+8],10h  
00007FF9FC1A7701  mov         rax,qword ptr [rbp+28h]  
00007FF9FC1A7705  mov         qword ptr [rbp+30h],rax  

可以看到dynamic的code遠比var的code誇張,而且性能也是成問題的。它這裏調用了CORINFO_HELP_NEWSFAST,實際上是進行了一個裝箱,也就是IL的box,運行時裏面的JIT_New。先傳入參數,然後返回裝箱後的對象地址也就是MethodTable,最後把0x10放入到&Methodtable+8地方。而var只是直接把0x10放入到棧。這麼看來,如果有性能需求,還是建議var,而慎用dynamic。

4.總結:
var和dynamic的不同點。
1.var被rosyln編譯前就確定了類型,而dynamic則是在CLR(這裏更嚴格點應該說是在JIT)裏面確定。
2.var只是一個簡單的值,而dynamic則被實例化成了一個對象,它的變量值是它對象的字段
3.var的性能遠遠大於dynamic的性能。


結尾

作者:江湖評談
歡迎關注我的公衆號:江湖評談(jianghupt),文章首發。
image

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章