Правильный Способ Преобразования Выражения> В Другое Выражение>


У меня есть два выражения.

У меня есть вход предиката типа Expression<Func<Foo, bool>>

Я хотел бы преобразовать исходное выражение В Тип Expression<Func<Bar, bool>>

Какова была бы логика, чтобы сделать это? Я пытался использовать Expression.Convert() , но я считаю, что делаю это неправильно.

1 2

1 ответ:

Для преобразования Expression<Func<Foo, bool>> в Expression<Func<Bar, bool>> Вам также понадобится Expression<Func<Bar, Foo>>, чтобы обработать преобразование.

То, что вы делаете, - это просто составление выражений. Составление выражений несколько сложнее, чем составление функций, где один может просто вызвать другой, передавая его результат в качестве параметра. Здесь мы должны заменить все экземпляры параметра второй функции телом первой:
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);
    }
}

Теперь мы можем сделать следующее:

Expression<Func<Foo, bool>> predicate = GetPrediate();
Expression<Func<Bar, Foo>> selector = GetSelector();
Expression<Func<Bar, bool>> newPredicate = selector.Compose(predicate);