2011-09-04 74 views
2

.NET表達式類型支持將調用表示爲由另一個表達式定義的函數,但是有沒有使用C#lambda表達式語法表達的方法?我可以生成一個表達式,編譯它並在另一個表達式中調用它,但是失去了被調用lambda表達式的「表達式」,並且調用表達式將只包含對匿名編譯函數的引用。如何使用C#lambda表達式語法調用另一個表達式?

也就是說,我想要做的是一樣的東西:

Expression<Func<int, int>> f = x => x + x; 
Expression<Func<int, int>> g = x => 2 + f(x); 

,但因爲它不是有效的直接調用的表達,我最接近的是:

Expression<Func<int, int>> f = x => x + x; 
var f_ = f.Compile(); 
Expression<Func<int, int>> g = x => 2 + f_(x); 

...這就失去了被調用函數f是一個表達式的事實。

回答

3

我不認爲這是目前可以做的編譯器的幫助(從C#4.0開始),但你當然可以用Expression.Invoke「親手」做。

創建一個將委託或lambda 表達式應用於參數表達式列表的InvocationExpression。

對你來說,這看起來是這樣的:

Expression<Func<int, int>> f = x => x + x; 

var parameter = Expression.Parameter(typeof(int),"y"); 
var body = Expression.Add(Expression.Constant(2), Expression.Invoke(f, parameter)); 

// Loosely speaking: y => 2 + f(y) 
var g = Expression.Lambda<Func<int, int>>(body, parameter); 

LINQKit提供Invoke/Expand擴展的方法是爲你做的腿工作,以便讓您的能力,爲此使用lambdas。這將讓你做的事:

Expression<Func<int, int>> f = x => x + x; 
Expression<Func<int, int>> g = x => 2 + f.Invoke(x); 

// Note: 'Inlines' the invocation into the target expression. 
var finalExpression = g.Expand(); 

..這是非常接近你原來想的語法。

關於InvocationExpression s的一點需要注意的是,一些LINQ提供者(如LINQ to Entities)根本不喜歡它們;所以你經常需要'擴展'被調用的表達式,以便它看起來像提供者的單個表達式。您當然可以手動完成此操作,但LINQKit可以再次與AsExpandable擴展一起使用。

+0

是的,我發現Expression.Invoke和InvocationExpression,這是我知道它可以代表。我很驚訝,沒有辦法用lambda表達式語法來表達它。實際上,使用lambda語法無法創建的所有表達式類型究竟是什麼,大多數LINQ提供者是否支持它們? – SoftMemes

+0

優秀的答案,謝謝! – SoftMemes