2013-10-03 50 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); 
相关问题