Don Tomato
Don Tomato

Reputation: 3509

Create lambda expression from another expression

I have the class:

public class Uid
{ 
    public Guid Id { get; set; }
}

And i've an expression:

void TestMethod<T, TUid>(Expression<Func<T,IUid>> exp1) where TUid : Uid
{
    ....
}

I know that exp1.Body is a PropertyExpression, it's something like that: (s) => s.UidProperty where UidProperty is a property of Uid type. Having it I should create the following expression:

Expression<Func<T, Guid>> myExp = (s) => s.UidProperty.Id

How to do that?

Upvotes: 0

Views: 120

Answers (1)

Servy
Servy

Reputation: 203802

We can use the following Compose method to take an expression that computes a value, and another expression that uses that output type as its input type, to create an expression that represents what would happen if the result of the first expression were passed to the second expression:

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");

    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);

    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

This allows us to write:

public Expression<Func<T, Guid>> TestMethod<T, TUid>(
    Expression<Func<T,IUid>> expression) 
    where TUid : Uid
{
    return expression.Compose(uid => uid.Id); 
}

Upvotes: 3

Related Questions