2014-07-01 76 views
2

我想構建一個使用另一個表達式的表達式,並且這會給我一個不錯的ToString()輸出。構建執行另一個表達式的表達式

與正常lambda表達式來表達,我想這樣做:

Func<string> extractFunc =() => "Marsh"; 
Func<bool> compareFunc =() => extractFunc() == "Mallow"; 

同樣的事情表達式:

Expression<Func<string>> extractExp =() => "Marsh"; 
Expression<Func<bool>> compareExp =() => extractExp.Compile()() == "Mallow"; 

執行compareExp.ToString()給我下面的輸出:

() => (Invoke(value(MyClass+<>c__DisplayClassb).extractExp.Compile()) == "Mallow") 

我想要的是類似的東西:

() => "March" == "Mallow" 

我應該寫什麼而不是extractExp.Compile()()

(我可能會使用某種ExpressionVisitor得到美麗的輸出。獎金,如果答案包括,但更重要的是如何合併兩個Expression秒)

回答

3

你在找什麼這裏是一個Compose方法,可以採取一個表達式,並將其映射成採用相同的輸入的方法,但是,從第一函數的結果執行操作:

public static Expression<Func<TResult>> 
    Compose<TIntermediate, TResult>(
    this Expression<Func<TIntermediate>> first, 
    Expression<Func<TIntermediate, TResult>> second) 
{ 
    return Expression.Lambda<Func<TResult>>(
     second.Body.Replace(second.Parameters[0], first.Body)); 
} 

此方法使用下面的方法來替代與另一個表達式的所有實例:

internal class ReplaceVisitor : ExpressionVisitor 
{ 
    private readonly Expression from, to; 
    public ReplaceVisitor(Expression from, Expression to) 
    { 
     this.from = from; 
     this.to = to; 
    } 
    public override Expression Visit(Expression node) 
    { 
     return node == from ? to : base.Visit(node); 
    } 
} 
public static Expression Replace(this Expression expression, 
    Expression searchEx, Expression replaceEx) 
{ 
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression); 
} 

現在你可以這樣寫:

Expression<Func<string>> extractExp =() => "Marsh"; 
Expression<Func<bool>> compareExp = extractExp.Compose(s => s == "Mallow"); 
+0

完美,謝謝! –