2013-07-23 26 views
4

我對DynamicMethods,Expression Trees和DLR之間的交互和關係有一些疑問。DynamicMethods,Expression Trees和DLR

  1. 我知道LambdaExpression.Compile在內部使用一個ILGenerator創建一個Delegate。但是,編譯的LambdaExpression和DynamicMethod之間有一些根本的區別。例如

    a。 DynamicMethods調用速度更快

    b。編譯的LambdaExpressions可以嵌入閉包(ConstantExpressions是非原始值)

    b。編譯的LambdaExpressions沒有DeclaringType。

    問題:

    a。爲什麼DynamicMethods比編譯的LambdaExpressions更快地調用?

    b。編譯的LambdaExpressions允許關閉的特別之處是什麼?當我使用非常量表達式時,表達式樹實際上是否生成閉包類?如果是這樣,這個生成的課程在哪裏?

    c。編譯的LambdaExpressions在哪裏(在運行時)?在哪裏支持他們的實施。它不能只是Reflection.Emit,可以嗎?

  2. 我知道動態關鍵字實際上只是一個用於發射CSharp CallSites,Binders等的編譯器技巧。據我所知,這些生成表達式樹並且還使用了C#編譯器的精簡版本。

    問題

    a。表達式樹一般是由CallSiteBinders生成的函數,還是在Microsoft.CSharp dll中具體實現和使用它們?

    b。這些表達式樹是由DynamicExpression節點組成的嗎?或者是其他東西?如果有其他事情,爲什麼?

    c。 C#編譯器的精簡版本在哪裏以及爲什麼會起作用?爲什麼以及它與定期調用LambdaExpression.Compile或DynamicMethods或任何類型的IL代有什麼不同?我可以理解CallSiteBinder如何用於構建表達式樹,但爲什麼在轉換髮生後需要C#編譯器?一旦它以表達式樹(這只是一個API)的形式,C#就完全可以做它。

+1

爲什麼你認爲'DynamicMethod'更快?你基於什麼聲稱? – svick

+1

另外,我想你提出的兩個問題並沒有真正相關。你可能應該問他們兩個不同的問題。 – svick

+0

我認爲他們更快的個人經驗,並在此引用http://stackoverflow.com/questions/1296683/curiosity-why-does-expression-when-compiled-run-faster-than-a-minimal-dyna(即使標題表明相反),這裏http://stackoverflow.com/questions/10673756/net-dynamic-method-best-performance。雖然這個差異很小,我一直認爲它只是在發射的IL上略有差異。 – Jeff

回答

3

我對dynamic瞭解不多,所以我只回答你的問題的第一部分。

爲什麼DynamicMethods更快地比編譯LambdaExpressions調用?

我會很驚訝,如果他們,因爲Expression.Compile()內部使用DynamicMethod

編譯好的LambdaExpressions允許閉包的特別之處是什麼?當我使用非常量表達式時,表達式樹實際上是否生成閉包類?如果是這樣,這個生成的課程在哪裏?

這很容易驗證。只需查看編譯表達式樹生成的委託的TargetMethod即可。你會注意到Target(和Method的第一個參數)是System.Runtime.CompilerServices.Closure。這是一個包含字段object[] Constants的類,其中存儲了來自ConstantExpression的非原始值。

編譯後的LambdaExpressions在哪裏(在運行時)?在哪裏支持他們的實施。它不能只是Reflection.Emit,可以嗎?

就像我之前說的,Expression.Compile()內部使用DynamicMethod。所以,是的,這只是Reflection.Emit。

+0

我在編譯的lambda表中看到了關於閉包類的一點。這回答了我的問題。謝謝。這也解釋了爲什麼JIT優化能爲一個普通DynamicMethod的VS由一個表達式樹創建了一個非常不同的效果(這是綁定到一個封閉類的實例) – Jeff

+0

我拆開表達式樹的API的closure類多,現在我把它(所有的點號1)。我想最簡單的方法來達到我的dlr問題的底部是做更多的反彙編。謝謝。我錯過了關於閉包類如何跟蹤常量的關鍵點。 – Jeff

2

嗯,我無法回答你所有的問題,但我可以回答其中的一些問題,我認爲這可能會回答你的大部分問題。也許至少它會給你足夠的信息來繼續研究。

爲什麼DynamicMethods更快地比編譯LambdaExpressions調用?

,我不認爲是這樣,也許你測量錯了,這是一個JIT'ing差異

什麼特別的編譯LambdaExpressions允許倒閉?當我使用非常量表達式時,表達式樹實際上是否生成閉包類?如果是這樣,這個生成的課程在哪裏?

這一個我不確定。我會假設Expression.Constant可以包含引用類型,那麼它是一個非問題,但如果它確實只能有值類型,那麼我會猜測編譯器只會生成一個表達式,其中變量在閉包中被捕獲只是作爲參數傳入。

編譯後的LambdaExpressions在哪裏(在運行時)?在哪裏支持他們的實施。它不能只是Reflection.Emit,可以嗎?

System.Linq.Expressions真的只是在Reflection.Emit的頂部的友好的API,他們只是存儲在內存中,就像Reflection.Emit的ERGO是在默認情況下(儘管Reflection.Emit的保存退出即可發射的代碼,我相信)

表達式樹一般是由CallSiteBinders生成的函數,還是它們在Microsoft.CSharp dll中的具體實現和用法?

我只是做了一些工作System.Dynamic,所以我不能回答這個問題,但它是我的理解是,CallSiteBinder只是緩存並調用表達,但通過實際發電關閉別的東西(即DynamicObject)。但是,再次,你可能比我更瞭解更多。

這些表達式樹是由DynamicExpression節點組成嗎?或者是其他東西?如果有其他事情,爲什麼?

不,動態仍受到.net中所有其他規則的約束。 Dynamic只是說「在運行時,當我做x時,去嘗試構建我通常會爲我編寫並執行的代碼。」像DynamicObject這樣的東西只是要構建一個普通的表達式樹,動態對象只是爲您提供一些元數據,以便您可以實際構建該樹(如返回類型,訪問類型,名稱等)。

在哪裏,爲什麼C#編譯器的精簡版開始發揮作用?爲什麼以及它與定期調用LambdaExpression.Compile或DynamicMethods或任何類型的IL代有什麼不同?我可以理解CallSiteBinder如何用於構建表達式樹,但爲什麼在轉換髮生後需要C#編譯器?一旦它以表達式樹(這只是一個API)的形式,C#就完全可以做它。

我不知道你的意思是剝離下來的編譯器或運行時實際上產生IL代碼(我認爲這是你在這裏後),所以我不認爲我可以回答這個。

然而,我會說,就像我之前說過的那樣:System.Linq.Expression的東西真的只是在Reflection.Emit之上的一個友好的API。表達式樹就是它需要去反射的信息,生成一個動態方法並將其返回給你。

+0

編譯器參考的精簡版本基於Eric Lippert所做的評論。應該注意到,在我的問題中,對不起。 – Jeff