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