从另一个表达式创建 lambda 表达式

Create lambda expression from another expression

我有 class:

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

我有一个表达式:

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

我知道 exp1.Body 是一个 PropertyExpression,它是这样的: (s) => s.UidProperty 其中 UidProperty 是 Uid 类型的 属性。有了它我应该创建以下表达式:

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

怎么做?

我们可以使用以下 Compose 方法来获取一个计算值的表达式,以及另一个使用该输出类型作为其输入类型的表达式,以创建一个表达式来表示如果结果会发生什么第一个表达式的传递给第二个表达式:

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);
    }
}

这允许我们写:

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