How to build a LambdaExpression from an existing LambdaExpression Without Compiling

北战南征 提交于 2019-12-03 16:14:28

I don't know if it's the best way, but you could do something like that:

public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
    Expression<Func<TContainer,TMember>> getMemberExpression, 
    Expression<Func<TMember,bool>> memberPredicateExpression)
{
    ParameterExpression x = Expression.Parameter(typeof(TContainer), "x");
    return Expression.Lambda<Func<TContainer, bool>>(
        Expression.Invoke(
            memberPredicateExpression,
            Expression.Invoke(
                getMemberExpression,
                x)),
        x);
}

Usage:

var expr = CreatePredicate(
    (Foo f) => f.Bar,
    bar => bar % 2 == 0);

Result:

x => Invoke(bar => ((bar % 2) == 0), Invoke(f => f.Bar, x))

I guess it would be better to get something like x => x.Bar % 2 == 0, but it would probably be significantly harder...


EDIT: actually it wasn't so hard with an expression visitor:

public Expression<Func<TContainer,bool>> CreatePredicate<TContainer,TMember>(
    Expression<Func<TContainer,TMember>> getMemberExpression, 
    Expression<Func<TMember,bool>> memberPredicateExpression)
{
    return CombineExpressionVisitor.Combine(
        getMemberExpression,
        memberPredicateExpression);
}

class CombineExpressionVisitor : ExpressionVisitor
{
    private readonly ParameterExpression _parameterToReplace;
    private readonly Expression _replacementExpression;
    private CombineExpressionVisitor(ParameterExpression parameterToReplace, Expression replacementExpression)
    {
        _parameterToReplace = parameterToReplace;
        _replacementExpression = replacementExpression;
    }

    public static Expression<Func<TSource, TResult>> Combine<TSource, TMember, TResult>(
        Expression<Func<TSource, TMember>> memberSelector,
        Expression<Func<TMember, TResult>> resultSelector)
    {
         var visitor = new CombineExpressionVisitor(
            resultSelector.Parameters[0],
            memberSelector.Body);
        return Expression.Lambda<Func<TSource, TResult>>(
            visitor.Visit(resultSelector.Body),
            memberSelector.Parameters);
    }

    protected override Expression VisitParameter(ParameterExpression parameter)
    {
        if (parameter == _parameterToReplace)
            return _replacementExpression;
        return base.VisitParameter(parameter);
    }
}

It gives the following expression:

f => ((f.Bar % 2) == 0)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!