Linq я должен вернуть список <T>или IEnumerable <T>, когда я еще могу сделать больше позже - PullRequest
5 голосов
/ 26 апреля 2011

У меня есть несколько методов, которые возвращают список T, например, GetAllEvents. В некоторых случаях мне нужно отфильтровать этот список событий (или каков мой Список) по дате или какому-либо другому свойству элементов.

Я знаю, что запросы LINQ могут быть «сцеплены» или иметь х строк, которые еще больше их уточняют, и запрос не будет выполняться до тех пор, пока вам не понадобится фактически использовать их в выражении, отличном от linq (пожалуйста, исправьте меня, если Я не прав в этом верующем.)

У меня вопрос: если мой метод GetAllXXX возвращает список того, что я получаю, то метод .ToList (), который я использую в конце моего кода GetAllXXX, выполняет LINQ? Должен ли я вернуть IEnumerable вместо этого? Если только в тех случаях, когда мне нужно сделать что-то еще с «результатами» ДО того, как запрос действительно запустится.

Вот пример моего беспокойства: я сказал 1000 событий. GetAllEvents извлечет все 1000 и выдаст мне их Список. Затем, в зависимости от того, на какой странице находится пользователь, могут отображаться только события на сегодня, на этой неделе или в определенной категории. В идеале, к моменту, когда я показываю пользователю 5 событий, происходящих сегодня, я не хочу передавать все 1000 по проводам, а затем обрезать их до 5, которые они действительно хотят. Да, я знаю, что на данный момент все это на стороне сервера, но если он все еще выделяет память для 1000, я пытаюсь избежать этого.

Есть указатели или предложения?

Ответы [ 3 ]

12 голосов
/ 26 апреля 2011

Возвращает IEnumerable.

Преобразование в List происходит быстро и безболезненно, плюс вы сохраняете свой интерфейс изолированным как от реализации ваших методов, так и от использования вывода.

Что касается вашего особого беспокойства - если будет дорого возвращать все 1000 событий и обрабатывать их на клиенте, то вам следует подумать о том, чтобы выполнить некоторую фильтрацию на сервере.У вас все еще может быть метод, который возвращает все события, но есть специализированные / оптимизированные версии, которые возвращают наиболее частые запросы.Сегодняшние события были бы хорошим примером.

9 голосов
/ 26 апреля 2011

Если вы превратите последовательность в список на сервере, то вы используете время и память на сервере, а затем передаете все это по проводам, а затем используете больше времени и памяти на клиенте для фильтрации списка.

Если вы просто возвращаете последовательность, то вы «решаете» свою проблему, создавая другую проблему. Теперь, когда клиент отправляется на фильтрацию списка, он должен совершить тысячу небольших обращений к серверу вместо одного дорогого обращения . Так же, как много информации передается по проводам и занимает гораздо больше времени со всеми накладными расходами на каждый удар.

Если вы хотите выполнить фильтрацию на сервере, то вы можете (1) создать пользовательский API, представляющий общие фильтры (easy), или (2) вместо этого вернуть IQueryable и реализовать поставщика LINQ. (сложно, но мощно.) IQueryable позволяет вам создать запрос на стороне клиента, отправить запрос по сети на сервер, выполнить запрос на сервере, а затем обработать только те результаты, которые хотел клиент.

Мой коллега Мэтт Уоррен написал целый ряд статей о том, как реализовать IQueryable; Я бы начал с этого.

8 голосов
/ 26 апреля 2011

Ответ Эрика Липперта хорош, но учтите, что вам не нужно реализовывать весь IQueryable, если вы просто хотите обеспечить некоторую фильтрацию на стороне сервера (даже настраиваемую фильтрацию).Вы можете создать LINQ-совместимый API более простым путем реализации только тех функций LINQ, которые вы фактически используете.Например, рассмотрим определение

interface IOneTripEnumerable<T> : IEnumerable<T>

, которое предоставляет только метод, совместимый с LINQ, с типом возврата IOneTripEnumerable

Реализация IOneTripEnumerable.Where будет возвращать новый объект, который также реализует IOneTripEnumerable и простосохраняет фильтр как элемент данных.Когда вызывается IOneTripEnumerable.GetEnumerator, вы можете упаковать фильтры и отправить их на сервер, а затем вернуть отфильтрованные результаты за один прием.

(Вы также можете реализовать политику кэширования на стороне клиента: если выхотите, чтобы последующие вызовы GetEnumerator возвращали перечислитель поверх тех же результатов, что и первоначальный вызов, просто сохраните результаты в перечисляемом объекте.)

Если у вас будет больше времени и вы увидите необходимость, вы можете дополнительно оптимизировать, добавивдополнительные методы LINQ, но просто контроль над Where (чтобы фильтрация происходила на сервере) и GetEnumerator (чтобы получить все результаты за один прием) может дать вам довольно хорошие результаты при низких затратах на внедрение.Вам не нужно реализовывать весь IQueryable.(Обратите внимание, что Count, Any и Take также являются очень хорошими кандидатами для двусторонней оптимизации и несложны в реализации).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...