Вы можете сделать это с помощью модифицированной версии Спецификации .Начните с интерфейса, который выражает результаты в процентах:
public interface ISpecification<T>
{
double GetPercentSatisfiedBy(T target);
}
Далее создайте спецификацию, которая применяет любое произвольное условие:
public sealed class Specification<T> : ISpecification<T>
{
private readonly Func<T, bool> _predicate;
public Specification(Func<T, bool> predicate)
{
_predicate = predicate;
}
public double GetPercentSatisfiedBy(T target)
{
return _predicate(target) ? 1 : 0;
}
}
Теперь создайте спецификацию, которая линейно объединяет результатыдругих спецификаций:
public sealed class CompositeSpecification<T> : ISpecification<T>
{
private readonly IList<ISpecification<T>> _specifications;
public CompositeSpecification(params ISpecification<T>[] specifications)
{
_specifications = specifications.ToList();
}
public double GetPercentSatisfiedBy(T target)
{
return _specifications.Average(
specification => specification.GetPercentSatisfiedBy(target));
}
}
Наконец, создайте спецификацию, которая содержит все ваши требуемые условия, и примените ее к списку Foo
объектов:
var specification = new CompositeSpecification<Foo>(
new Specification<Foo>(foo => foo.Quantity >= 2),
new Specification<Foo>(foo => foo.Value < 2),
new Specification<Foo>(foo => foo.Category == "Blah"),
new Specification<Foo>(foo => foo.Quality > 5));
var foos = new List<Foo> { ... };
var results =
from foo in foos
let percentSatisfied = specification.GetPercentSatisfiedBy(foo)
orderby percentSatisfied descending
select new
{
Foo = foo,
PercentSatisfied = percentSatisfied
};
Этот дизайн поддерживает спецификациипроизвольной сложности.