Il problema è che è possibile non solo "e"/"o" loro, perché è necessario riscrivere gli interni per cambiare i parametri; se si utilizzada e1
, ma il parametro da e2
, non funzionerà, poiché lo .Body
di e1
fa riferimento a un'istanza di parametro completamente indipendente che non è definita. Questo è più evidente se si utilizza:
Expression<Func<MyEntity, bool>> e1 = i => i.FName.Contains("john");
Expression<Func<MyEntity, bool>> e2 = j => j.LName.Contains("smith");
(notare la differenza tra e1
utilizzando i
e e2
utilizzando j
)
Se li combiniamo senza dover riscrivere il parametro, si otterrebbe l'assurdo:
Expression<Func<MyEntity, bool>> combined =
i => i.FName.Contains("john") && j.LName.Contains("smith");
(woah .... dove ha j
provengono da?)
TUTTAVIA; il problema è identico indipendentemente dal nome del parametro : è ancora un parametro diverso.
E poiché l'espressione è immutabile, non è possibile scambiarla "sul posto".
Il trucco è quello di utilizzare un "visitatore" per riscrivere i nodi, in questo modo:
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);
}
}
Combine * come * - "e anche"? –
sì, e anche. Voglio combinarli in runtime. – PickleRick