2013-02-13 71 views
3

The C# Programming language比爾·瓦格納說:動態綁定VS類型推斷

很多人混淆了類型推斷動態bindig。類型 推斷是靜態綁定的。編譯器在編譯時確定類型 。例如:

var i = 5;    //i is an int (Compiler performs type inference) 
Console.WriteLine(i); //Static binding to Console.WriteLine(int) 

編譯器推斷出我是一個整數。所有綁定變量 我使用靜態綁定。

現在,鑑於此信息,我自己編造的動態之情況:

 dynamic i = 5;  //Compiler punts 
     Console.WriteLine(i);//This is now dynamically bound 

我們知道類型推斷靜態綁定。這意味着動態變量無法使用類型推斷來確定類型。如何在不使用類型推斷的情況下解決動態類型?

更新
要嘗試,並在運行時,我們必須設法弄清楚我是什麼類型的正確澄清......?因爲我分配了文字5,運行時可以推斷iint。不是那種類型推斷而不是動態綁定?

+0

動態的基礎類型(這是一種語言結構,在元數據中除了屬性外沒有表示)是'System.Object'。這是C#編譯器魔術,它允許您動態調用方法並訪問其上的字段(在本例中爲盒裝整型),而無需自己進行反射。 – 2013-02-13 17:56:07

回答

6

比爾製作有什麼區別?

,比爾正在的區別是,很多人都認爲:

var x = Whatever(); 
x.Foo(); 

將制定出在運行時有什麼方法foo調用基於對象的類型,通過無論在運行時返回。這不是真的;這將是

dynamic x = Whatever(); 
x.Foo(); 

var只是意味着「找出在編譯時的類型和替代它」,而不是「工作了在運行時」。

所以,如果我有

dynamic i = 5; 
Console.WriteLine(i); 

會發生什麼?

編譯器生成的代碼在道德上是這樣的:

object i = (object)5; 
DynamicCallSite callSite = new DynamicCallSite(typeof(Console), "WriteLine")); 
callSite.Invoke(i); 

它比更復雜一點;呼叫站點被緩存了一件事。但是這給你它的味道。

調用方法通過GetType詢問i的類型,然後啓動可以理解反射對象的特殊版本的C#編譯器。它確實對名爲WriteLineConsole的成員重載分辨率,並且確定Console.WriteLine本來被稱爲i的那個超載首先被鍵入爲int。

然後它會生成一個表示該調用的表達式樹,將表達式樹編譯成一個委託,將其緩存在調用站點中,並調用委託。

第二次執行此操作時,緩存的調用站點將在其高速緩存中查找並看到最後一次i爲int,並調用了特定的委託。因此,它第二次跳過創建呼叫站點並進行重載解析,並調用委託。

欲瞭解更多信息,請參見:

http://ericlippert.com/2012/10/22/a-method-group-of-one/

http://ericlippert.com/2012/11/05/dynamic-contagion-part-one/

http://ericlippert.com/2012/11/09/dynamic-contagion-part-two/

要素上歷史的角度可以從克里斯和薩姆的博客獲得:

http://blogs.msdn.com/b/cburrows/archive/tags/dynamic/

http://blogs.msdn.com/b/samng/archive/tags/dynamic/

他們做了很多實現;然而這些文章中的一些反映了過時的設計選擇。令人遺憾的是,我們從未使用過「幽靈方法」算法。 (不是一個很好的算法,而是一個偉大的名字!)

+0

我明白了,所以'動態'並不經過7.5.2節定義的類型推斷過程。相反,'i.GetType()'用於在運行時確定類型。 – 2013-02-13 18:10:53

+0

或者更確切地說......在你更新之後,他會比較'var'和'dynamic'。這就說得通了! – 2013-02-13 18:16:11

+1

@ P.Brian.Mackey:第7.5.2節是*通用方法類型推斷*。 Bill正在討論的部分是關於*隱式鍵入的局部變量聲明*的第8.5.1節。 – 2013-02-13 18:56:41