De acuerdo con "Domain Drive Design" de Eric Evan, necesita el patrón de especificación. Algo como esto
public interface ISpecification<T>
{
bool Matches(T instance);
string GetSql();
}
public class ProductCategoryNameSpecification : ISpecification<Product>
{
readonly string CategoryName;
public ProductCategoryNameSpecification(string categoryName)
{
CategoryName = categoryName;
}
public bool Matches(Product instance)
{
return instance.Category.Name == CategoryName;
}
public string GetSql()
{
return "CategoryName like '" + { escaped CategoryName } + "'";
}
}
su repositorio puede ser llamado ahora con las especificaciones
var specifications = new List<ISpecification<Product>>();
specifications.Add(
new ProductCategoryNameSpecification("Tops"));
specifications.Add(
new ProductColorSpecification("Blue"));
var products = ProductRepository.GetBySpecifications(specifications);
También podría crear una clase CompositeSpecification genérica que contendría especificaciones sub y un indicador de qué operador lógico aplicar a ellos Y/O
Sin embargo, estaría más inclinado a combinar expresiones LINQ.
Actualización - Ejemplo de LINQ en tiempo de ejecución
var product = Expression.Parameter(typeof(Product), "product");
var categoryNameExpression = Expression.Equal(
Expression.Property(product, "CategoryName"),
Expression.Constant("Tops"));
Se puede añadir una "y" al igual que
var colorExpression = Expression.Equal(
Expression.Property(product, "Color"),
Expression.Constant("Red"));
var andExpression = Expression.And(categoryNameExpression, colorExpression);
Por último se puede convertir esta expresión en un predicado y luego ejecutarlo. ..
var predicate =
(Func<Product, bool>)Expression.Lambda(andExpression, product).Compile();
var query = Enumerable.Where(YourDataContext.Products, predicate);
foreach(Product currentProduct in query)
meh(currentProduct);
Probablemente no compile porque lo he escrito directamente en el navegador, pero creo que generalmente es correcto.
Otra actualización :-)
List<Product> products = new List<Product>();
products.Add(new Product { CategoryName = "Tops", Color = "Red" });
products.Add(new Product { CategoryName = "Tops", Color = "Gree" });
products.Add(new Product { CategoryName = "Trousers", Color = "Red" });
var query = (IEnumerable<Product>)products;
query = query.Where(p => p.CategoryName == "Tops");
query = query.Where(p => p.Color == "Red");
foreach (Product p in query)
Console.WriteLine(p.CategoryName + "/" + p.Color);
Console.ReadLine();
En este caso se evaluarán en la memoria porque la fuente es una lista, pero si su fuente era un contexto de datos que apoyó Linq2SQL por ejemplo, me parece esto evaluaría usando SQL.
Aún puede utilizar el patrón de Especificación para hacer explícitos sus conceptos.
public class Specification<T>
{
IEnumerable<T> AppendToQuery(IEnumerable<T> query);
}
La principal diferencia entre los dos enfoques es que el último se basa una consulta conocido basado en las propiedades explícitas, mientras que el primero podría ser utilizado para construir una consulta de cualquier estructura (como la construcción de una consulta en su totalidad a partir de XML por ejemplo.)
Esto debería ser suficiente para empezar :-)
[Filtro Diseño Modelo Con Ejemplo] (http://www.singhajit.com/filter-design-pattern/) –