Выражение Linq из Lambda: укажите параметр явно

1

Я хочу встроить дерево выражений, например

Expression<Func<MyObject, double>> expr = (o) => o.Value;

в большее дерево выражений, генерируемое парсером. Однако параметр o уже определен внутри внешнего дерева выражений. В принципе мне пришлось бы искать тело expr и заменять все вхождения параметра экземпляром из дерева синтаксического анализа.

Есть ли встроенный способ сделать это? Или существует даже способ прямого генерации лямбда-выражения при указании экземпляра параметра заранее?

Теги:
lambda
expression-trees

1 ответ

2
Лучший ответ

Вы не можете напрямую поручить компилятору повторно использовать существующие экземпляры ParameterExpression, но после этого вы можете их заменить (фактически создавая новые деревья выражений).

Встроенный ExpressionVisitor помогает при тяжелом подъеме; это не-посетитель, который вы получаете, чтобы добавить необходимые функции. В этом случае вам нужно указать ему заменить экземпляры ParameterExpression, чтобы вы могли:

// Sorry for the atrocious formatting, wanted to keep it scrollbar-free
class ParameterReplacementVisitor : ExpressionVisitor
{
    private readonly
    IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>>
    replacementMap;

    public ParameterReplacementVisitor(
        IEnumerable<KeyValuePair<ParameterExpression, ParameterExpression>> map)
    {
        this.replacementMap = map;
    }

    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        return Expression.Lambda<T>(
            Visit(node.Body),
            node.Parameters.Select(Visit).Cast<ParameterExpression>());
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        var replacement = this.replacementMap
                              .Where(p => p.Key == node)
                              .DefaultIfEmpty()
                              .First().Value;
        return base.VisitParameter(replacement ?? node);
    }
}

которые вы можете использовать следующим образом:

Expression<Func<int, bool>> e1 = i => true;
Expression<Func<int, bool>> e2 = j => false;

Console.WriteLine(e1.Parameters[0] == e2.Parameters[0]); // false

var replacements = new Dictionary<ParameterExpression, ParameterExpression>
{
    { e1.Parameters[0], e2.Parameters[0] }
};

var replacer = new ParameterReplacementVisitor(replacements);
var e3 = replacer.VisitAndConvert(e1, "replacing parameters");

Console.WriteLine(e3.Parameters[0] == e2.Parameters[0]); // true
  • 0
    Спасибо! Работает как положено. Я надеялся, что будет прямой путь, но это сделает это.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню