今天讀到了《CLR via C#》中動態基元類型的章節,剛好剛剛在候選區看到了一篇《爲何能夠說Java語言是準動態語言?》的文章,其文中說Java依賴反射能夠稱爲‘準動態語言’,而C#是靜態語言。程序員
我先不說結論,先來看一下什麼是動態語言。編程
引用互動百科的詞條:函數
動態語言,準確地說,是指程序在運行時能夠改變其結構:新的函數能夠被引進,已有的函數能夠被刪除等在結構上的變化。好比衆所周知的ECMAScript(JavaScript)即是一個動態語言。除此以外如Ruby、Python等也都屬於動態語言,而C、C++等語言則不屬於動態語言。性能
好比咱們在JavaScript裏面能夠這樣寫:spa
1 var temp = {}; 2 temp.FuncA = function(){ 3 console.log('FuncA Invoked') 4 } 5 temp.Name = 'JavaScript';
在以上代碼中,對象temp是一個匿名對象,不具備類型結構。而後咱們爲temp動態追加了一個函數 FuncA和一個屬性Name 。之因此能夠這樣寫,是由於JavaScript是一種解釋型語言,全部的代碼只有在運行時纔會被解釋器編譯。而C語言,Java語言以及.Net 3.5及之前版本的C#語言,是運行前已經被編譯爲機器語言,所以全部的對象在編譯時就必須有一個類型定義,編譯器沒有辦法推斷動態調度的成員,也就沒有辦法編譯代碼了。這一類語言通常被稱爲靜態語言。.net
很長一段時間以來,這兩類語言也都相安無事,本身管着本身的一畝三分地。然而,動態編程對程序員的誘惑實在是太大了,不少工程師就會想,咱們能不能讓編譯器經過某種方式編譯動態調度的對象呢?答案是確定的。在.net CLR還不支持動態調度的時候,就已經有工程師經過CodeDom動態編譯技術和反射模擬了動態調度類型。code
雖然這種方式性能十分差勁,用起來也十分的繁瑣,但也爲後來的動態基元類型的實現提供了理論基礎。對象
咱們前面說了,動態語言是運行時編譯的,因此纔可以動態調度。因此咱們能夠肯定如下幾點:blog
1. 動態調度對象須要在運行時才能肯定其結構ip
2. 動態調度對象須要動態編譯,不可以預編譯
3. 經過動態編譯和反射技術,咱們能夠以一種醜陋的方式模擬動態調度的過程
因此,若是在JITCompiler中,對須要動態調度的對象進行動態編譯不就可以在預編譯語言中實現動態調度了嗎?
在.net 4.0及以後的版本中,咱們能夠這樣寫:
1 public void Main() 2 { 3 dynamic temp = new System.Dynamic.ExpandObject(); 4 temp.FuncA = () =>{ 5 Console.WriteLine("FuncA Involved"); 6 }; 7 temp.Name = "CSharp Dynamic Dispatch"; 8 }
當編譯器編譯到這段代碼的時候,不會將其編譯爲機器碼,而是在程序集中加入payload,並在運行到這裏時調用.NET 編譯器動態編譯,獲得當前的動態對象的實例,而後經過IL的內存操做訪問其中的成員,使性能比反射高出不少,實現起來也更加優雅了。
說到這裏咱們就可以得出結論,CLR版本4.0以後的C#已經符合全部動態語言的定義,能夠被稱爲一種動態語言了。甚至若是你喜歡,能夠徹底把C#當作動態語言來用,雖然可能在某些場景下會有必定的性能損失,但跟反射比起來,仍是會優秀不少的。