2015-06-18 50 views
2

LINQ表達式樹我想使用表達式目錄樹動態創建調用拉姆達的方法調用拉姆達。下面的代碼對ComposeLambda函數的第一次調用運行正常,但第二次調用失敗,並顯示以下錯誤消息。如何使用C#/。NET

數目不正確的用於調用方法提供的參數 '的Int32 lambda_method(System.Runtime.CompilerServices.Closure,Int32)將'

{ 
    Func<int, int> innerLambda = i => i + 1;  
    var composedLambda = ComposeLambda(innerLambda); 
    Console.WriteLine(composedLambda.DynamicInvoke(0)); 
    var composedLambda2 = ComposeLambda(composedLambda); 
    Console.WriteLine(composedLambda2.DynamicInvoke(0)); 
} 

private static Delegate ComposeLambda(Delegate innerLambda) 
{ 
    Func<int, int> outerLambda = i => i + 2; 
    var parameter = Expression.Parameter(typeof (int)); 
    var callInner = Expression.Call(innerLambda.GetMethodInfo(), parameter); 
    var callOuter = Expression.Call(outerLambda.GetMethodInfo(), callInner); 
    var composedLambdaType = typeof (Func<,>).MakeGenericType(typeof (int), typeof (int)); 
    var composedLambdaExpression = Expression.Lambda(composedLambdaType, callOuter, parameter); 
    var composedLambda = composedLambdaExpression.Compile(); 
    return composedLambda; 
} 

我怎樣才能獲得,並通過此封閉對象?

+1

@ jp2code這是在4.5:[GetMethodInfo](https://msdn.microsoft.com/en-我們/庫/ system.reflection.runtimereflectionextensions.getmethodinfo(v = vs.110)的.aspx) –

+0

不要使用'Expression.Call(innerLambda.GetMethodInfo(),...)',這只是自找麻煩。調用的委託,而不是 - 你有沒有業務委託的「方法」亂搞 - 你不僅失去了目標(以實例方法很重要),但你也侵犯隱私(匿名方法是內部的或私有的,例如)。在這種情況下,你沒有通過閉合參數的方法:) – Luaan

+0

@Luaan表達式樹是浪費時間的低層次的東西 - 那就是他們是什麼那裏 –

回答

7

不要使用Expression.Call(innerLambda.GetMethodInfo(), ...),這只是自找麻煩。調用委託代替 - 你沒有業務搞亂委託的「方法」 - 不僅你失去了目標(在實例方法中非常重要),但你也侵犯了隱私(例如匿名方法是內部的或私有的,例如)。

在這種情況下,你沒有關閉參數傳遞到:)這應該是從錯誤消息,而明顯的方法 - 它表明你的實際方法的簽名(包括關閉)。

如果使用Expression.Invoke(如你應該代表),它按預期工作:

void Main() 
{ 
    Func<int, int> innerLambda = i => i + 1;  
    var composedLambda = ComposeLambda(innerLambda); 
    Console.WriteLine(composedLambda.DynamicInvoke(0)); 
    var composedLambda2 = ComposeLambda(composedLambda); 
    Console.WriteLine(composedLambda2.DynamicInvoke(0)); 
} 

private static Delegate ComposeLambda(Delegate innerLambda) 
{ 
    Func<int, int> outerLambda = i => i + 2; 
    var parameter = Expression.Parameter(typeof (int)); 

    var callInner = Expression.Invoke(Expression.Constant(innerLambda), parameter); 
    var callOuter = Expression.Invoke(Expression.Constant(outerLambda), callInner); 
    var composedLambdaType = typeof (Func<,>).MakeGenericType(typeof (int), typeof (int)); 
    var composedLambdaExpression = Expression.Lambda(composedLambdaType, callOuter, parameter); 
    var composedLambda = composedLambdaExpression.Compile(); 
    return composedLambda; 
} 

除此之外,如果你知道在編譯時正確的委託類型,不要用Delegate 。在這種情況下,這是非常容易的使用Func<int, int>,然後你就可以調用作爲composedLambda2(0),例如:

private static Func<int, int> ComposeLambda(Func<int, int> innerLambda) 
{ 
    Func<int, int> outerLambda = i => i + 2; 
    var parameter = Expression.Parameter(typeof (int)); 

    var callInner = Expression.Invoke(Expression.Constant(innerLambda), parameter); 
    var callOuter = Expression.Invoke(Expression.Constant(outerLambda), callInner); 

    var composedLambdaExpression = Expression.Lambda<Func<int, int>>(callOuter, parameter); 
    return composedLambdaExpression.Compile(); 
} 
+0

哪裏會是一個好去處......瞭解這是做什麼,它是爲了什麼,它叫什麼?這只是把我吹走了。 – jp2code

+1

@ jp2code我不知道任何很好的解釋或教程。這些被稱爲「表達式樹」 - 在MSDN上的基本介紹在https://msdn.microsoft.com/en-us/library/bb397951.aspx。嘗試http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx,以獲得一些解釋和示例。 – Luaan

+0

@Luaan謝謝你的幫助。當然,如果我不被強迫,我不會使用表達樹;當然,我總是儘可能具體地說明這些類型。但是,如果有人寫出非常通用的代碼片段,那麼最糟糕的情況就是這樣。 –