Esta entrada es para que no se me olvide. Siempre que trabajo con árboles de expresiones me paso la primera hora mirando la documentación tratando de recordar las 2 malditas líneas que te permiten combinar 2 expresiones Lambda.
public interface ISpecification<T> where T : class
{
ISpecification<T> AND(ISpecification<T> s);
ISpecification<T> AND(Expression<Func<T, bool>> criteria);
ISpecification<T> OR(ISpecification<T> s);
ISpecification<T> OR(Expression<Func<T, bool>> criteria);
Func<T, bool> IsSatisfied();
Expression<Func<T, bool>> matchingCriteria();
}
public sealed class Specification<T> : ISpecification<T> where T : class
{
private Expression<Func<T, bool>> _matchingCriteria;
public Specification(Expression<Func<T, bool>> matchingCriteria)
{
if (matchingCriteria == null) { throw new ArgumentNullException("matchingCriteria"); }
_matchingCriteria = matchingCriteria;
}
public Func<T, bool> IsSatisfied()
{
return _matchingCriteria.Compile();
}
public Expression<Func<T, bool>> matchingCriteria()
{
return _matchingCriteria;
}
public ISpecification<T> AND(ISpecification<T> criteria)
{
var invokedExpr = Expression.Invoke(criteria.matchingCriteria(), _matchingCriteria.Parameters.Cast<Expression>());
return new Specification<T>(Expression.Lambda<Func<T, bool>>(Expression.AndAlso(_matchingCriteria.Body, invokedExpr), _matchingCriteria.Parameters));
}
public ISpecification<T> AND(Expression<Func<T, bool>> criteria)
{
var invokedExpr = Expression.Invoke(criteria, _matchingCriteria.Parameters.Cast<Expression>());
return new Specification<T>(Expression.Lambda<Func<T, bool>>(Expression.AndAlso(_matchingCriteria.Body, invokedExpr), _matchingCriteria.Parameters));
}
public ISpecification<T> OR(ISpecification<T> s)
{
var invokedExpr = Expression.Invoke(s.matchingCriteria(), _matchingCriteria.Parameters.Cast<Expression>());
return new Specification<T>(Expression.Lambda<Func<T, bool>>(Expression.OrElse(_matchingCriteria.Body, invokedExpr), _matchingCriteria.Parameters));
}
public ISpecification<T> OR(Expression<Func<T, bool>> criteria)
{
var invokedExpr = Expression.Invoke(criteria, _matchingCriteria.Parameters.Cast<Expression>());
return new Specification<T>(Expression.Lambda<Func<T, bool>>(Expression.OrElse(_matchingCriteria.Body, invokedExpr), _matchingCriteria.Parameters));
}
}
internal class Program
{
private static void Main(string[] args)
{
List<persona> listaPers = new List<persona>();
listaPers.Add(new persona { nombre = "jose", edad = 17, localidad = "caceres" });
listaPers.Add(new persona { nombre = "juan", edad = 19, localidad = "caceres" });
listaPers.Add(new persona { nombre = "manolo", edad = 19, localidad = "badajoz" });
listaPers.Add(new persona { nombre = "alfonso", edad = 17, localidad = "don benito" });
listaPers.Add(new persona { nombre = "pepe", edad = 34, localidad = "navalmoral" });
ISpecification<persona> CacereñosMenoresde18 = new Specification<persona>(p => p.edad < 18).AND(p => p.localidad == "caceres");
ISpecification<persona> PacensesMayoresDe18 = new Specification<persona>(p => p.edad > 18).AND(p => p.localidad == "badajoz");
ISpecification<persona> CacereñosMenoresde18ORPacensesMayoresDe18 = CacereñosMenoresde18.OR(PacensesMayoresDe18);
var res = listaPers.Where(CacereñosMenoresde18ORPacensesMayoresDe18.IsSatisfied());
foreach (persona p in res)
{
Console.WriteLine(p.nombre);
}
Console.Read();
}
}
No hay comentarios:
Publicar un comentario