我不确定这是否严格 currying,但我基本上想要实现以下目标。给定Expression
:
Expression<Func<T1, T2, TResult>> expression
我想传入一个参数并生成相应的Expression
,其中此参数的值是固定的。结果表达式应该在功能上等同于expression
,除了它应该包含少一个参数。
这个结果表达式如下所示:
Expression<Func<T2, TResult>> curriedExpression;
我已经尝试了这个,但它不起作用,因为Expression
没有隐式转换为lambda表达式:
curriedExpression = b => expression(fixedValueForT1, b);
请注意,curriedExpression
不应包含对expression
的调用;它应该包含重复的逻辑,除了固定值。
我希望这是有道理的。如果这个含糊不清或者解释不清楚,请告诉我。
答案 0 :(得分: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))
答案 1 :(得分:0)
我刚刚发现使用LinqKit可能是可以的,您可以通过NuGet here获取。{/ p>
我目前没有时间尝试这个例子,但它可能值得研究,所以你不必使用像ExpressionVisitor
这样的解决方案。
答案 2 :(得分:0)
这是@ jon-diaet实现的替代方案,具有以下优点/缺点:
优点:
缺点:
object
)。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;
}
所以在@ jon-skeet的例子中我们会使用:
var partiallyApplied = Curry<int, int>(original, 0, 10);