Использование спецификации открыло для меня новый мир в создании приложений Репозитории предоставляют удобное решение для доступа к данным. Однако за многолетний опыт разработки, побывав в нескольких компаниях, сменив кучу проектов я НЕ ВСТРЕЧАЛ паттерн "Спецификация" совместно с паттерном "Репозиторий". Плюсы: использование абстракций для доступа к данным – правильное решение; спецификация предлагает стандартизованный подход к созданию репозиториев, что облегчает разработку, сопровождение и масштабирование приложений; добавление разных вариаций запросов данных сводится к созданию одной  строки кода; изменение запросов производится на уровне пользовательского кода — нет необходимости менять код репозитория; паттерн спецификация позволяет более гибко работать с фильтрами и операциями And, Or, Not и т. д.   Уверен, ребята в комментариях найдут минусы у этого подхода.Хотя от себя добавлю, что для оптимизированных запросов к БД, код нужно дорабатывать (хотя бы в том плане, чтобы можно было управлять порядком включения зависимых сущностей .Include(_ => _.AnotherEntity)) Схема моей реализации шаблона представлена на Рисунке 1 ниже. Для моих потребностей она оказалась вполне достаточной и покрывающий все кейсы использования. Хочу обратить внимание, что у интерфейса нет методов And() Or() Not(). Благодаря  этому нет нарушения Interface Segregation Principle. Всего 4 класса и пара вспомогательных позволяют достичь ОГРОМНОЙ гибкости в формировании запросов. Для корректного преобразования наших будущих условий в деревья выражений, с которыми работает любой фреймворк доступа к данным, использую Expression<Func>.  Метод  Expression<Func<TEntity, object>>[] GetIncludes()позволяет возвращать функции включения объектов в запрос. Метод  Expression<Func<TEntity, bool>>? SatisfiedBy() занимается проверкой объекта на соответствие условиям перечисленным в Func<TEntity, bool>. Метод  OrderModel[] GetOrderModels() возвращает DTO, хранящие сортирующие выражения, для сортировки результатов запроса.  Абстрактный класс BaseSpecification<TEntity> содержит реализацию свойств Skip и Take , а также перегрузки операторов И (&) и ИЛИ (|). Благодаря чему нет необходимости внедрять методы And() и Or() в базовый интерфейс.   Самой простой в реализации является DirectSpecification<TEntity>. Она позволяет создавать одно условное выражение для выбора данных.  "И" и "ИЛИ" спецификации между собой очень похожи, их код приведен ниже. Их конструкторы принимают в аргументах две другие спецификации ISpecification<TEntity>, которые могут быть как составными (тоже "И" или "ИЛИ"), так и простые спецификации (например две реализации через DirectSpecification<TEntity>), так и комбинации простой и составной спецификации.    Обе они реализуют метод SatisfiedBy()  базового класса SpecificationBase<TEntity>, объединяя два Expression<Func>, полученных от вызовов методов двух спецификаций, которые были переданы в конструктор. Схема моей реализации репозиториев совместно с использованием паттерна "Спецификация" представлена на Рисунке 2 ниже. В целом первые 4 метода (Get, GetStrict, List, Any), представленные в IRepository<TEntity>, реализуются единожды в базовом абстрактном классе StorageBase<TEntity> и больше никогда не изменятся.  Ниже приведены реализации методов (Get, GetStrict, List, Any), они максимально просты и понятны, но при этом максимально "гибкие", благодаря спецификациям. А теперь представляю гвоздь, опору, связующее звено без которого ничего не могло бы работать вместе. Да) это класс SpecificationEvaluator Этот класс позволяет формировать запросы на основе переданной спецификации к базе данных, хранилищам в RAM или другим источникам данных. Реализация для IEnumerableполностью аналогична, ее не буду приводить, для облегчения восприятия. Для упрощения понимания использования, приведу конкретный пример. Представим, что у нас есть класс Man - человек со свойствами имя, возраст и пол:  Предположим, на нашем сайте мы реализуем множественный фильтр по каждому из полей этой сущности. Различные варианты самых распространенных репозиториев, которые я считаю сложными, неподдерживаемыми. Конечно, когда речь идет о такой задаче (множественная фильтрация), то каждый хороший разработчик задумается о том, как бы мне поменьше кода написать.  Однако в начале разработки системы, может не стоять такой задачи явно, и полей может быть меньше, что не будет критичным для создания кода репозитория и т.п. Буду показывать на примере RAM хранилища данных для более легкого воспроизведения. Вариант выше содержит много метода Get, но даже они не покрывают всех возможных вариантов фильтрации для трех полей, которых с учетом операторов И и ИЛИ уже я насчитал 11, а что будет для большего количества полей, а если еще нужны методы Any() , List() с такими же условиями фильтрации? Другой подход уменьшает количество методов в репозитории, но увеличивает количество строк кода в каждом из них. Он тоже не является оптимальным. Привел реализацию только метода Get с И оператором. Нужно также реализовать Get с ИЛИ и Get с вариациями И и ИЛИ. Все это займет кучу кода и при добавлении нового свойства в класс Man, придется изменять каждый из этих методов или добавлять новые. А теперь покажу как будет выглядеть репозиторий с применением спецификаций. Как можно заметить "репозиторию" совершенно все равно на то, какой запрос приходит ему на вход. Он занимается только получением и отдачей данных. Вот так мы добавили в нашу систему новую сущность и репозиторий для работы с ней. Теперь покажу как можно использовать этот репозиторий. Для удобства создам статический класс, создающий спецификации: Тогда применение будет выглядеть следующим образом: На мой взгляд это выглядит намного симпатичнее и понятнее, что нам вернется и как будет выглядеть запрос. В заключение, паттерн спецификация и паттерн репозиторий являются мощными инструментами, которые могут помочь создавать более эффективные, удобные и надежные программные системы. Они позволяют облегчить процесс разработки, повысить качество кода и упростить его сопровождение. Для меня они открыли совершенно новый мир, где репозитории создаются по щелчку пальцев и их поддержка не вызывает проблем. Советы, пожелания и рекомендации буду рад увидеть в комментариях. UPD. Благодаря внимательным комментаторам, прикрепляю забытый класс, позволяющий объединять вместе Expression: