Problem polega na tym, że nie można po prostu „i”/„lub” je, bo trzeba re-write elementy wewnętrzne do zmiany parametrów; jeśli użyjesz .Body
z e1
, ale parametr z e2
, to nie zadziała - ponieważ .Body
z e1
odnosi się do zupełnie niepowiązanej instancji parametru, która nie jest zdefiniowana. Jest to bardziej oczywiste jeśli używasz:
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith");
(zwrócić uwagę na różnicę pomiędzy e1
użyciu i
i e2
użyciu j
)
Jeśli połączymy je bez przepisywania parametru, chcielibyśmy uzyskać bezsensowne:
Expression<Func<MyEntity, bool>> combined =
i => i.FName.Contains("john") && j.LName.Contains("smith");
(woah .... skąd j
pochodzi?)
JEDNA; problem jest identyczny, niezależnie od wartości parametru : nadal jest to inny parametr.
A ponieważ wyrażenie jest niezmienne, nie można po prostu zamienić go "na miejscu".
Sztuką jest wykorzystanie "gościem" przepisać węzły, tak:
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);
}
}
Kombajny * jak * - "a także"? –
tak, andAlso. Chcę je połączyć w czasie wykonywania. – PickleRick