I'm not sure if this is strictly currying, but I'm basically wanting to achieve the following. Given an Expression
:
Expression<Func<T1, T2, TResult>> expression
I want to pass in one of the arguments and produce a corresponding Expression
where the value for this parameter is fixed. The resulting expression should be functionally equivalent to expression
except that it should contain one less parameter.
This resulting expression would look something like this:
Expression<Func<T2, TResult>> curriedExpression;
I've tried this, but it doesn't work because an Expression
doesn't implicitly convert to a lambda expression:
curriedExpression = b => expression(fixedValueForT1, b);
Note that curriedExpression
shouldn't contain a call to expression
; it should contain duplicated logic except with the fixed value.
I hope that makes sense. Let me know if this is ambiguous or not explained well.
I think you can just derive from the ExpressionVisitor
class in a simple way. Here's a proof of concept - it may be overly simplistic, but I think it's what you're after:
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);
}
}
Output:
Original: (x, y) => (MethodX(x) + MethodY(y))
Partially applied: y => (MethodX(10) + MethodY(y))
See more on this question at Stackoverflow