В моем веб-приложении ASP.net MVC4 я использую IEnumerables, пытаясь следовать мантре для программирования интерфейса, а не реализации.
Return IEnumerable(Of Student)
против
Return New List(Of Student)
Люди говорят мне использовать List, а не IEnumerable, потому что списки заставляют выполнять запрос, а IEumerable - нет.
Это действительно лучшая практика? Есть ли альтернатива? Я чувствую себя странно, используя конкретные объекты, где может быть использован интерфейс. Оправдано ли мое странное чувство?
.net
programming-practices
asp.net-mvc
entity-framework
Роуэн Фриман
источник
источник
Ответы:
Бывают случаи, когда выполнение
ToList()
запросов в linq может быть важным для обеспечения выполнения ваших запросов в то время и в том порядке, в котором вы ожидаете их выполнить. Эти сценарии, однако, редки, и никто не должен слишком беспокоиться о них, пока они действительно не столкнутся с ними.Короче говоря, используйте в
IEnumerable
любое время,IList
когда вам нужна только итерация, используйте, когда вам нужно напрямую индексировать и вам нужен массив с динамическим размером (если вам нужна индексация для массива с фиксированным размером, просто используйте стандартный массив).Что же касается времени выполнения вещь, вы всегда можете использовать список в качестве
IEnumerable
переменной, так что не стесняйтесь возвращатьIEnumerable
посредством производства.ToList();
, или передать в качестве параметра какIEnumerable
путем выполнения.ToList()
наIEnumerable
в силу исполнения прямо тогда и там. Просто будьте осторожны, чтобы каждый раз, когда вы принудительно.ToList()
выполняли выполнение, не зависали отIEnumerable
переменной, которую вы только что сделали, и выполняли ее снова, иначе вы в итоге удвоите количество итераций в своем запросе LINQ.Что касается MVC, то здесь особо отмечать нечего. Он будет следовать тем же правилам времени выполнения, что и остальная часть .NET, я думаю, что у вас может быть кто-то, кто был немного смущен, вызванным семантикой отложенного выполнения в прошлом, и обвинил его в том, что MVC говорит, что это как-то связано, но это не. Семантика отложенного выполнения сначала смущает всех (и даже на некоторое время потом; они могут быть довольно сложными). Опять же, просто не беспокойтесь об этом, пока вы действительно не позаботитесь о том, чтобы запрос LINQ не выполнялся дважды или не требовал, чтобы он выполнялся в определенном порядке относительно другого кода, после чего назначьте вашу переменную себе. ToList () форсировать исполнение, и все будет в порядке.
источник
List
обход вокругList
означает, что содержимое списка будет изменено. Если вы хотите вернуть коллекцию, используйтеIReadOnlyCollection
.List
предназначен для использования внутри методов и для обмена между методами, которые изменяют список. Это оно!Есть две проблемы.
К тому времени, когда цикл «Данные процесса» будет достигнут, запрос может перестать быть действительным. Например, если запрос выполняется для DataContext, который уже был удален, ваш код выдаст исключение. Подобные вещи становятся очень запутанными, когда вы обрабатываете запрос в другом контексте, чем тот, где вы его создали.
Вторая проблема заключается в том, что ваше соединение не будет освобождено, пока не завершится цикл обработки данных. Это проблема, только если «Данные процесса» сложны. Это упоминается по адресу http://msdn.microsoft.com/en-us/library/bb386929.aspx :
Таким образом, именно эти проблемы побуждают вас убедиться, что запрос действительно выполняется, например, с помощью вызова
ToList()
. Тем не менее, как полагает Джимми , ничто не мешает вам вернуть свой список в виде IEnumerable.Как правило, я рекомендую избегать итерации по IEnumerable более одного раза. Предполагая, что потребители вашего кода следуют этому правилу, я не считаю, что кто-то может дважды зайти в базу данных, выполнив запрос дважды.
источник
Другое преимущество перечисления
IEnumerable
ранних исключений будет выброшено в соответствующем месте. Это помогает отладке.Например, если вы получили исключение взаимоблокировки в одном из ваших представлений Razor, на самом деле это не было бы так ясно, как если бы исключение произошло во время одного из ваших методов доступа к данным.
источник
IEnumerable
который может бросить, вероятно, делает ошибку. ОтложенныеIEnumerable
методы должны быть разделены на два: один не отложенный метод проверяет параметры и устанавливает их, выбрасывая при необходимости (скажем, из-за пустого аргумента). Затем он возвращает вызов к частной реализации , которая является отложенной. Я не думаю, что мои комментарии полностью расходятся с вашим ответом, но я думаю, что вы упустили важный аспект в своем ответе, а именно семантическое значение использованияIEnumerable
противList
(мутация) противIReadOnlyCollection
(без пользы для отсрочка) .