Подтвердить что ты не робот

Как объединить два лямбда-выражения без использования метода Invoke?

У меня есть два лямбда-выражения:

Expression<Func<MyEntity, bool>> e1 = i = >i.FName.Contain("john");

а также

Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contain("smith");

тип я происходит от моих сущностей poco, которые нельзя использовать с invoke. Я хочу объединить их во время выполнения.

Я хочу объединить эти выражения во время выполнения таким же образом, как:

Expression<Func<MyEntity, bool>> e3 = Combine(e1,e2);
4b9b3361

Ответ 1

Проблема заключается в том, что вы не можете просто "и" / "или", потому что вам нужно переписать внутренние элементы для изменения параметров; если вы используете .Body из e1, но параметр из e2, он не будет работать, потому что .Body of e1 ссылается на полностью несвязанный экземпляр параметра, который не определен. Это более очевидно, если вы используете:

Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith");

(обратите внимание на разницу между e1 с помощью i и e2 с помощью j)

Если мы объединим их без перезаписи параметра, мы получим бессмысленный:

Expression<Func<MyEntity, bool>> combined =
         i => i.FName.Contains("john") && j.LName.Contains("smith");

(woah.... откуда взялось j?)

ОДНАКО; проблема идентична независимо от имени параметра: это все еще другой параметр.

И поскольку выражение неизменное, вы не можете просто поменять его "на месте".

Фокус в том, чтобы использовать "посетителя" для перезаписи узлов, например:

using System;
using System.Linq.Expressions;

class SwapVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public SwapVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

static class Program
{
    static void Main()
    {
        Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
        Expression<Func<MyEntity, bool>> e2 = i => i.LName.Contains("smith");

        // rewrite e1, using the parameter from e2; "&&"
        var lambda1 = Expression.Lambda<Func<MyEntity, bool>>(Expression.AndAlso(
            new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
            e2.Body), e2.Parameters);

        // rewrite e1, using the parameter from e2; "||"
        var lambda2 = Expression.Lambda<Func<MyEntity, bool>>(Expression.OrElse(
            new SwapVisitor(e1.Parameters[0], e2.Parameters[0]).Visit(e1.Body),
            e2.Body), e2.Parameters);
    }
}

Ответ 2

using (MyDataBaseEntities db = new MyDataBaseEntities())
    {
            {
                if (db.People.Any(p => p.FirstName == FirstNameText.Text && p.LastName == LastNameText.Text))
                            {
                                 //Do something
                            }
            }      
    }

Может быть, с простым выражением, если?

Кстати, я новичок, извините, если мой ответ глупый.