2016-04-29 50 views
5

在我的圖書館之一,我有一個從表達式返回的MethodInfo代碼:爲什麼不同版本的.NET(或編譯器)的生成相同的表達不同的表達式樹

public MethodInfo GetMethod(Expression expression) 
{ 
    var lambdaExpression = (LambdaExpression)expression; 
    var unaryExpression = (UnaryExpression)lambdaExpression.Body; 
    var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; 
    var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last(); 
    return (MethodInfo)methodInfoExpression.Value; 
} 

我有一個一系列的輔助功能,使這樣的方法調用以下:

public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression) 
{ 
    return GetMethod(expression); 
} 

這將使語法如下:

var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool); 

這很好,直到我最近將庫升級到.Net 4.6.1和最新的c#編譯器。

在以前版本的.NET,表達將是下面的形式:

{x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))} 

因此我的代碼將查找methodInfoExpression作爲methodCallExpression的最後一個參數。

現在,在淨4.6.1(最新的C#編譯器),編譯器似乎產生不同形式的表達:因爲最後一個參數是不是一個常量表達式

{x => Convert(Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String).CreateDelegate(System.Func`2[System.String, System.Boolean], x))} 

我當前的代碼中斷。看着它 - 很容易解決,只需改變

var methodInfoExpression = (ConstantExpression)methodCallExpression.Object; 

顯然,實現getMethod功能是相當脆弱的,可作改動編譯器如何生成表達式。我很好奇改變的原因,以及我如何重構GetMethod,以便它對編譯器生成的表達式樹更有彈性。

+1

你應該真的發佈示例代碼,在提供示例時進行編譯。如果您希望幫助更有效地編寫該方法,則應實際描述需要執行的操作,而不是僅顯示其非工作版本。 – Servy

回答

4

我很好奇,爲改變

隨着.NET 4.5的原因有來自MethodInfo作出委託的方式有兩種:

  1. 實例方法對MethodInfo ,和
  2. Delegate.CreateDelegate靜態方法

看起來像微軟決定從使用#2切換到使用#1,無論出於何種原因(它可能更有效)。

我該如何重構GetMethod,以便它對編譯器生成的表達式樹更有彈性?

您可以使用expression tree visitor,然後查找方法信息。

+0

非常有幫助。謝謝! –

相關問題