前言
這個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),文章首發。