Skip to content

Instantly share code, notes, and snippets.

@lydonchandra
Last active July 16, 2021 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lydonchandra/f6e089f619cfd6b4149fc7779ace5082 to your computer and use it in GitHub Desktop.
Save lydonchandra/f6e089f619cfd6b4149fc7779ace5082 to your computer and use it in GitHub Desktop.
linqpad - specs filter
void Main()
{
//nameof(UserQuery.Brand).Dump();
//Enum.GetName(UserQuery.Brand.Adidas).Dump();
List<Product> products = new()
{
new Product { Color = Color.Green, Size = Size.Small, Brand = Brand.Adidas },
new Product { Color = Color.Red, Size = Size.Large, Brand = Brand.Adidas },
new Product { Color = Color.Red, Size = Size.Medium, Brand = Brand.Nike },
};
ColorSpecification colorSpec = new(Color.Red);
SizeSpecification sizeSpec = new(Size.Medium);
BrandSpecification brandSpec = new(Brand.Nike);
//var specs2 = colorSpec & sizeSpec & brandSpec;
//IFilter<Product>.Filter(products, specs2).Dump();
//
var spec1 = new EnumSpecification<Product, Color>(Color.Red);
var spec2 = new EnumSpecification<Product, Brand>(Brand.Nike);
IFilter<Product>.Filter(products, spec1 & spec2).Dump();
}
public enum Color {
Red, Green, Blue
}
public enum Size {
Small, Medium, Large
}
public enum Brand {
Adidas,
Nike
}
public class EnumSpecification<Product, TEnum>
: Specification<Product>
where TEnum : System.Enum
{
private TEnum enumSpec;
public EnumSpecification(TEnum enumSpec) => this.enumSpec = enumSpec;
public override bool IsSatisfied(Product item)
{
// reflect on Product object and get Color/Size/Brand enum field
var propName = typeof(TEnum).Name;
var prop = item.GetType().GetProperty(propName)
?? throw new ArgumentNullException($"{propName} does not exist in Product");
var propVal = prop.GetValue(item, null);
TEnum propValEnum = (TEnum) Enum.Parse(typeof(TEnum), propVal.ToString()); // <--------------- better way to parse enum ?
if(EqualityComparer<TEnum>.Default.Equals(propValEnum, this.enumSpec)) {
return true;
}
return false;
}
}
public class Product {
public Guid Id { get; } = Guid.NewGuid();
public Color Color { get; set;}
public Size Size { get; set;}
public Brand Brand { get; set; }
}
public abstract class Specification<T> {
public abstract bool IsSatisfied(T item);
public static Specification<T> operator &(Specification<T> first, Specification<T> second)
{
return new AndSpecification<T>(
new Specification<T>[] {first, second} );
}
}
public class AndSpecification<T> : Specification<T>
{
private Specification<T>[] specs;
public AndSpecification(params Specification<T>[] specs)
=> this.specs = specs;
public override bool IsSatisfied(T item)
=> this.specs.All(spec => spec.IsSatisfied(item));
}
public interface IFilter<T> {
public static IEnumerable<T> Filter(IEnumerable<T> items, Specification<T> spec) {
foreach(var item in items) {
if(spec.IsSatisfied(item)) {
yield return item;
}
}
}
}
public class ColorSpecification : Specification<Product>
{
private Color color;
public ColorSpecification(Color color) => this.color = color;
public override bool IsSatisfied(Product item) => (item.Color == this.color);
}
public class SizeSpecification: Specification<Product>
{
private Size size;
public SizeSpecification(Size size) => this.size = size;
public override bool IsSatisfied(Product item) => (this.size == item.Size);
}
public class BrandSpecification: Specification<Product>
{
private Brand brand;
public BrandSpecification(Brand brand) => this.brand = brand;
public override bool IsSatisfied(Product item) => (this.brand == item.Brand);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment