20

我有两个 lambda 表达式:

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

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

i 类型来自我的 poco 实体,不能与调用一起使用。我想在运行时结合这些。

我想在运行时以类似的方式组合这些表达式:

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

2 回答 2

59

问题是你不能只是“和”/“或”它们,因为你需要重写内部来改变参数;如果您使用.Bodyfrom e1,但使用参数from e2,它将不起作用 - 因为.Bodyofe1引用了一个未定义的完全不相关的参数实例。如果您使用以下内容,这会更加明显:

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

e1(注意usingie2using之间的区别j

如果我们在不重写参数的情况下将它们组合起来,我们会得到无意义的结果:

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

(哇......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);
    }
}
于 2012-05-16T07:08:26.400 回答
-3

也许用一个简单的 if 语句?

using (MyDataBaseEntities db = new MyDataBaseEntities())
{
if (db.People.Any(p => p.FirstName == FirstNameText.Text && p.LastName == LastNameText.Text))
    {
        //Do something
    }
}    
于 2019-03-13T11:44:16.113 回答