Практические правила для того, когда вызывать ToList при возврате результатов LINQ
Я ищу правила большого пальца для вызова ToList/ToArray/MemoizeAll(Rx)
на IEnumerables
, в отличие от возврата самого запроса при возврате IEnumerable
чего-либо.
Часто я нахожу, что лучше просто вернуть запрос и позволить вызывающей стороне решить, нужен ли список, или нет, но иногда он может вернуться и укусить вас сзади из-за ленивой природы linq.
Я хочу собрать рекомендации, такие как:
Вызовите ToList, если:
- вы создаете новые объекты (например, в избранном)
- у вас есть побочные эффекты в вашем запросе
В противном случае верните запрос
5 ответов
Во-первых, вы никогда не должны иметь побочных эффектов в запросе. Это худшая практика. Запросы должны отвечать на вопрос, а не давать эффект.
Ответ на ваш вопрос: вернуть запрос, когда вызывающий ожидает запрос; вернуть список, когда вызывающий ожидает список. Когда вы разрабатываете свой метод, решите, что с большей вероятностью понадобится вызывающей стороне, реализуйте это, а затем задокументируйте это.
При рассмотрении вопроса о том, хочет ли звонящий запрос или список, подумайте о различиях между запросами и списками:
запросы всегда актуальны. Если объекты / базы данных / все, что запрашивает запрос, изменяет его содержимое, то результаты запроса изменятся, если вы снова запустите запрос. Списки не меняют своего содержимого и поэтому списки устаревают. Если вашему абоненту требуются последние данные, отправьте им запрос. Если им требуется снимок данных, которые они могут проверить на досуге, предоставьте им список.
Запросы потенциально дороги для выполнения, чтобы получить свои результаты. Списки дешевы, чтобы получить их результаты. Если вызывающий абонент, вероятно, захочет запросить результат много раз и ожидает, что каждый раз получит одни и те же результаты, предоставьте им список.
Построение запроса происходит быстро. Выполнение запроса для построения списка выполняется медленно. Список всегда получает все результаты запроса. Вызывающий может захотеть дополнительно ограничить запрос, скажем, взяв только первые десять элементов. Если вызывающая сторона не хочет или нуждается в полной итерации по всему запросу, то дайте им запрос; не принимайте это решение от их имени и не предоставьте им список.
запросы крошечные. Списки большие. Многие запросы могут быть повторены по n элементам в пространстве O(1); список из n элементов занимает O(n) места. Если результирующий набор огромен, то помещение его в список, вероятно, неэффективно.
и так далее.
Нет простого ответа. Ответ аналогичен ответу на любую другую проблему проектирования: рассмотрите все плюсы и минусы каждого возможного решения в контексте того, что, скорее всего, требуется пользователю функции, а затем выберите разумное компромиссное решение.
Вернуть ToList, если:
- Вы не хотите или заботитесь о ленивой оценке запроса.
Редактировать:
Также верните ToList, если:
- Вы используете какую-то инфраструктуру Linq to SQL (LLBLGen, EF и т. Д.), И вам необходимо выполнить операцию над списком, которую среда не может преобразовать в SQL.
Используйте ToList, если вам нужно запускать пользовательские функции для данных, возвращаемых LINQ to SQL.
Использование ToList
прежде чем выйти using
блок, который держит ваш DataContext
,
Возврат запроса, когда вызывающая сторона, вероятно, / обязана предоставить дополнительные критерии фильтрации, которые будут использоваться индексами для уменьшения числа строк результатов и / или ввода-вывода базы данных.
Вы ToList()
когда вы хотите список объектов для вашего результата.