Given a lambda that takes an Identification object, and returns a property:
Expression<Func<Identification, object>> fx = _ => _.Id;
And a conversion lambda that converts an object into an Identification instance:
ParameterExpression p = Expression.Parameter(typeof(object), "o");
Expression @new = Expression.Lambda(Expression.Convert(p, typeof(Identification)), p);
How do I build a new lambda that executes @new
(getting out the Identification Instance) and passes the result into fx
. I need @new
's result to bind to the first parameter of fx
somehow, and I cannot find an example.
I need the result to be an Expression
, it should be of type Expression<Func<object, object>>
and it should convert the inbound parameter to an Identification
and then get the Id
property.
Firstly, note that this is easier if you type @new
appropriately, i.e.:
LambdaExpression @new = ...
since that provides easy access to @new.Body
and @new.Parameters
; that done,
Expression.Invoke
can be useful here:
var combinedParam = Expression.Parameter(typeof(object), "o");
var combined = Expression.Lambda<Func<object, object>>(
Expression.Invoke(fx,
Expression.Invoke(@new, combinedParam)), combinedParam);
although for a cleaner expression, you can also use ExpressionVisitor
to completely replace the inner expressions:
var injected = new SwapVisitor(fx.Parameters[0], @new.Body).Visit(fx.Body);
var combined = Expression.Lambda<Func<object, object>>(injected,@new.Parameters);
with:
class SwapVisitor : ExpressionVisitor {
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to) {
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node) {
return node == from ? to : base.Visit(node);
}
}
what this does is:
fx.Body
tree, replacing all instances of _
(the parameter) with the @new.Body
(note that this will contain references to the o
parameter (aka p
)@new
, which ensures that the values we injected will be bound correctlyUsing the code from Marc Gravell's answer, you can simplify this really nicely with a helper function:
public static class ExpressionHelper {
public static Expression<Func<TFrom, TTo>> Chain<TFrom, TMiddle, TTo>(
this Expression<Func<TFrom, TMiddle>> first,
Expression<Func<TMiddle, TTo>> second
) {
return Expression.Lambda<Func<TFrom, TTo>>(
new SwapVisitor(second.Parameters[0], first.Body).Visit(second.Body),
first.Parameters
);
}
private class SwapVisitor : ExpressionVisitor {
private readonly Expression _from;
private readonly Expression _to;
public SwapVisitor(Expression from, Expression to) {
_from = from;
_to = to;
}
public override Expression Visit(Expression node) {
return node == _from ? _to : base.Visit(node);
}
}
}
Now look how clean that is!
var valueSelector = new Expression<Func<MyTable, int>>(o => o.Value);
var intSelector = new Expression<Func<int, bool>>(x => x > 5);
var selector = valueSelector.Chain<MyTable, int, bool>(intSelector);
And it works with Entity Framework and other things that need a clean Expression
that doesn't try to invoke a Func
within it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With