Как объединить два лямбда

Возможный дубликат:
объединение двух выражений lamba в С#

У меня есть два следующих выражения:

Expression<Func<string, bool>> expr1 = s => s.Length == 5;
Expression<Func<string, bool>> expr2 = s => s == "someString";

Теперь мне нужно объединить их с OR. Что-то вроде этого:

Expression.Or(expr1, expr2)

Есть ли способ сделать это похожим на код выше, например:

expr1 || expr2

Я понимаю, что в этом примере я могу просто объединить его в первую очередь:

Expression<Func<string, bool>> expr = s => s.Length == 5 || s == "someString"

но я не могу сделать это в своем реальном коде, поскольку я получаю expr1 и expr2 в качестве аргументов метода.

Ответ 1

Чтобы закончить ответ Эрика, используйте новый ExpressionVisitor, введенный в .NET 4, а не пользовательский перезаписывающий файл:

internal class ParameterReplacer : ExpressionVisitor {
    private readonly ParameterExpression _parameter;

    protected override Expression VisitParameter(ParameterExpression node) {
        return base.VisitParameter(_parameter);
    }

    internal ParameterReplacer(ParameterExpression parameter) {
        _parameter = parameter;
    }
}

class Program {

    static void Main(string[] args) {
        Expression<Func<string, bool>> expr1 = s => s.Length == 5;
        Expression<Func<string, bool>> expr2 = s => s == "someString";
        var paramExpr = Expression.Parameter(typeof(string));
        var exprBody = Expression.Or(expr1.Body, expr2.Body);
        exprBody = (BinaryExpression) new ParameterReplacer(paramExpr).Visit(exprBody);
        var finalExpr = Expression.Lambda<Func<string, bool>>(exprBody, paramExpr);
    }

}

Ответ 2

Проблема состоит в том, что параметры "s" в каждой лямбда имеют одно и то же имя и один и тот же тип, но это разные параметры. Параметры имеют идентификатор ссылки, а не идентификатор ценности. Простое объединение двух тел существующих деревьев выражений в третье дерево выражений эффективно делает:

s => s1.Length == 5 || s2 == "somestring"

что не имеет никакого смысла. То, что вы хотите сделать, это написать посетителю, который выполняет поиск и замену параметра s новым параметром, который затем будет использоваться в качестве параметра для нового выражения лямбда.

См. этот родственный вопрос для более подробной информации:

Сочетание двух лямбда-выражений в С#