2013-10-03 83 views
1

我不確定這是不是嚴格柯里,但我基本上想要實現以下。給定一個Expression我怎樣才能將表情注入另一個表情?

Expression<Func<T1, T2, TResult>> expression 

我想在自變量一個通過,併產生相應的Expression其中用於該參數的值是固定的。得到的表達式應該在功能上等同於expression,只是它應該包含少一個參數。

這導致表達式將是這個樣子:

Expression<Func<T2, TResult>> curriedExpression; 

我已經試過這一點,但它不工作,因爲Expression不會隱式轉換爲Lambda表達式:

curriedExpression = b => expression(fixedValueForT1, b); 

請注意curriedExpression不應包含對expression的調用;除了固定值之外,它應該包含重複的邏輯。

我希望這是有道理的。讓我知道這是否含糊不清或解釋不好。

回答

3

我想你可以用簡單的方法從ExpressionVisitor類中派生出來。這裏有一個概念證明 - 這可能過於簡單,但我認爲這是你以後:

using System; 
using System.Linq.Expressions; 

class Test 
{ 
    static void Main() 
    { 
     Expression<Func<int, int, int>> original = (x, y) => MethodX(x) + MethodY(y); 
     Console.WriteLine("Original: {0}", original); 
     var partiallyApplied = ApplyPartial(original, 10); 
     Console.WriteLine("Partially applied: {0}", partiallyApplied); 
    } 

    static int MethodX(int x) 
    { 
     return x + 1; 
    } 

    static int MethodY(int x) 
    { 
     return -x; 
    } 

    static Expression<Func<T2, TResult>> ApplyPartial<T1, T2, TResult> 
     (Expression<Func<T1, T2, TResult>> expression, T1 value) 
    { 
     var parameter = expression.Parameters[0]; 
     var constant = Expression.Constant(value, parameter.Type); 
     var visitor = new ReplacementVisitor(parameter, constant); 
     var newBody = visitor.Visit(expression.Body); 
     return Expression.Lambda<Func<T2, TResult>>(newBody, expression.Parameters[1]); 
    } 
} 

class ReplacementVisitor : ExpressionVisitor 
{ 
    private readonly Expression original, replacement; 

    public ReplacementVisitor(Expression original, Expression replacement) 
    { 
     this.original = original; 
     this.replacement = replacement; 
    } 

    public override Expression Visit(Expression node) 
    { 
     return node == original ? replacement : base.Visit(node); 
    } 
} 

輸出:

Original: (x, y) => (MethodX(x) + MethodY(y)) 
Partially applied: y => (MethodX(10) + MethodY(y)) 
+0

感謝。有沒有更接近你用'Func'做同樣的簡單方法? – Sam

+0

我擔心沒有簡單的方法,當你使用表達式處理句法結構時,這總是一個相當複雜的業務! –

0

我才發現,原來這可能是可能使用LinqKit ,你可以通過NuGet here獲得。

我沒有時間在這個例子中嘗試一下,但它可能值得一看,所以你不必使用像ExpressionVisitor這樣的解決方案。

0

這是@喬恩 - 飛碟實施替代方案,具有以下優點/缺點:

優點:

  • 輸入表達式可以具有0..N任何類型的參數。
  • 通過指定被替換的參數的索引,您可以對任何這些參數進行咖喱。

缺點:

  • 你失去編譯時類型安全(輸入表達式沒有通用的參數,該指數可以是超出範圍和替換是object)。
  • 您必須指定返回的lambda表達式的類型。所以在@例子
private Expression<TLambda> Curry<TLambda>(
    LambdaExpression searchExpression, 
    int replacedParameterIndex, 
    object replacement) 
{ 
    var parameter = searchExpression.Parameters[replacedParameterIndex]; 
    var constant = Expression.Constant(replacement, parameter.Type); 
    var visitor = new ReplacementVisitor(parameter, constant); 
    var newBody = visitor.Visit(searchExpression.Body); 
    var lambda = Expression.Lambda<TLambda>(newBody, searchExpression.Parameters.Except(new[] { parameter })); 

    return lambda; 
} 

喬恩 - 飛碟,我們將使用:

var partiallyApplied = Curry<int, int>(original, 0, 10); 
相關問題