У меня есть некоторые сомнения по поводу того, как работают счетчики и LINQ. Рассмотрим эти два простых выбора:
List<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct().ToList();
или
IEnumerable<Animal> sel = (from animal in Animals
join race in Species
on animal.SpeciesKey equals race.SpeciesKey
select animal).Distinct();
Я изменил имена своих оригинальных объектов, чтобы это выглядело как более общий пример. Сам запрос не так важен. Я хочу спросить вот что:
foreach (Animal animal in sel) { /*do stuff*/ }
Я заметил, что если я использую
IEnumerable
, когда я отлаживаю и проверяю «sel», который в данном случае является IEnumerable, у него есть несколько интересных членов: «inner», «external», «innerKeySelector» и «outerKeySelector», эти последние 2 появляются быть делегатами. «Внутренний» член не имеет экземпляров «Animal», а содержит «Species», что было очень странно для меня. «Внешний» член содержит экземпляры «Animal». Я предполагаю, что два делегата определяют, что входит и что выходит из этого?Я заметил, что если я использую «Distinct», «inner» содержит 6 элементов (это неверно, так как только 2 являются Distinct), но «external» действительно содержит правильные значения. Опять же, вероятно, делегированные методы определяют это, но это немного больше, чем я знаю об IEnumerable.
Самое главное, какой из двух вариантов является лучшим с точки зрения производительности?
Злой Конвертация Списка через .ToList()
?
Или, может быть, использовать перечислитель напрямую?
Если вы можете, пожалуйста, объясните немного или добавьте несколько ссылок, которые объясняют это использование IEnumerable.
источник
IEnumerable<T>
будет LINQ-To-Objects после первой части, означающей, что все обнаруженные объекты должны быть возвращены для запуска Feline. С другой стороны, anIQuertable<T>
позволит уточнить запрос, опуская только пятнистых кошек.Есть очень хорошая статья, написанная: TechBlog Клаудио Бернаскони здесь: Когда использовать IEnumerable, ICollection, IList и List
Вот некоторые основные моменты о сценариях и функциях:
источник
List
является реализацияIList
и как таковой имеет дополнительные функциональные возможности сверх тех , что вIList
(напримерSort
,Find
,InsertRange
). Если вы заставите себя использоватьIList
болееList
, вы потеряете эти методы , которые вам может потребоватьсяIReadOnlyCollection<T>
[]
.Класс, который реализует
IEnumerable
позволяет вам использоватьforeach
синтаксис.По сути, у него есть метод для получения следующего элемента в коллекции. Ему не нужно, чтобы вся коллекция находилась в памяти, и он не знает, сколько в нем предметов,
foreach
просто продолжает получать следующий предмет, пока он не закончится.Это может быть очень полезно в определенных обстоятельствах, например, в массивной таблице базы данных вы не хотите копировать все это в память, прежде чем начинать обрабатывать строки.
Теперь
List
реализуетIEnumerable
, но представляет всю коллекцию в памяти. Если у вас естьIEnumerable
и вы звоните,.ToList()
вы создаете новый список с содержимым перечисления в памяти.Ваше выражение linq возвращает перечисление, и по умолчанию выражение выполняется, когда вы выполняете итерацию, используя
foreach
. AnIEnumerable
выполняется оператор LINQ , когда вы итерируетеforeach
, но вы можете заставить его итерацию быстрее , используя.ToList()
.Вот что я имею в виду:
источник
foreach
пока List будет идти, скажем, по индексу. Теперь, если я хотел бы знать кол / длина отthing
заранее, IEnumerable не поможет, не так ли?List
иArray
реализуемIEnumerable
. Вы можете думатьIEnumerable
как о наименьшем общем знаменателе, который работает как для коллекций памяти, так и для больших, которые получают по одному элементу за раз. Когда вы звоните,IEnumerable.Count()
вы, возможно, звоните быстро.Length
или просматриваете всю коллекцию - дело в том, чтоIEnumerable
вы не знаете. Это может быть проблемой, но если вы просто идете кforeach
этому, то вам все равно - ваш код будет работать сArray
илиDataReader
тем же.Никто не упомянул одно принципиальное различие, иронично ответил на вопрос, закрытый как дубликат этого.
См. Практическая разница между списком и IEnumerable
источник
Самая важная вещь, которую нужно понять, это то, что, используя Linq, запрос не оценивается сразу. Он запускается только как часть итерации, что приводит
IEnumerable<T>
кforeach
- это то, что делают все странные делегаты.Итак, первый пример оценивает запрос немедленно, вызывая
ToList
и помещая результаты запроса в список.Второй пример возвращает объект
IEnumerable<T>
, содержащий всю информацию, необходимую для запуска запроса позже.С точки зрения производительности ответ зависит . Если вам нужно, чтобы результаты оценивались сразу (скажем, вы изменяете структуры, которые запрашиваете позже, или если вы не хотите, чтобы итерация выполнялась
IEnumerable<T>
долго), используйте список. Остальное используйIEnumerable<T>
. По умолчанию следует использовать оценку по требованию во втором примере, поскольку он обычно использует меньше памяти, если только нет особой причины для сохранения результатов в списке.источник
Join
делает его работу - внутренняя и внешняя - две стороны соединения. Как правило, не беспокойтесь о том, что на самом деле вIEnumerables
, так как это будет полностью отличаться от вашего фактического кода. Заботьтесь о фактическом выводе, только когда перебираете его :)Преимущество IEnumerable - отложенное выполнение (обычно с базами данных). Запрос не будет выполнен до тех пор, пока вы на самом деле не выполните цикл данных. Это запрос, ожидающий, пока он не понадобится (он же ленивая загрузка).
Если вы вызовете ToList, запрос будет выполнен или «материализован», как я хотел бы сказать.
Есть плюсы и минусы для обоих. Если вы вызываете ToList, вы можете удалить некоторую загадку относительно того, когда запрос будет выполнен. Если вы придерживаетесь IEnumerable, вы получаете преимущество в том, что программа не выполняет никакой работы до тех пор, пока она на самом деле не потребуется.
источник
Я поделюсь одной неправильно используемой концепцией, к которой я попал за один день:
Ожидаемый результат
Фактический результат
объяснение
Как и в других ответах, оценка результата была отложена до вызова
ToList
или аналогичных методов вызова, напримерToArray
.Таким образом, я могу переписать код в этом случае как:
Play Arround
https://repl.it/E8Ki/0
источник
IEnumerable
работает, но теперь не больше , так как я знаю , как;)Если все, что вы хотите сделать, это перечислить их, используйте
IEnumerable
.Помните, однако, что изменение исходной перечисляемой коллекции является опасной операцией - в этом случае вы захотите
ToList
сначала. Это создаст новый элемент списка для каждого элемента в памяти, перечисляяIEnumerable
и, следовательно, менее производительный, если вы перечисляете только один раз - но более безопасный, а иногда иList
методы удобны (например, в произвольном доступе).источник
IEnumerable
, то сначала создание списка (и повторение по нему) означает, что вы выполняете итерации по элементам дважды . Поэтому, если вы не хотите выполнять операции, которые более эффективны в списке, это действительно означает снижение производительности..ToList()
помогает здесь;)В дополнение ко всем ответам, опубликованным выше, вот мои два цента. Есть много других типов, кроме List, которые реализуют IEnumerable, такие как ICollection, ArrayList и т. Д. Поэтому, если у нас есть IEnumerable в качестве параметра любого метода, мы можем передать в функцию любые типы коллекций. Т.е. у нас может быть метод для работы с абстракцией, а не какая-то конкретная реализация.
источник
Во многих случаях (таких как бесконечный список или очень большой список) IEnumerable не может быть преобразован в список. Наиболее очевидными примерами являются все простые числа, все пользователи Facebook с их деталями или все элементы на eBay.
Разница в том, что объекты «List» хранятся «прямо здесь и сейчас», тогда как объекты «IEnumerable» работают «только по одному за раз». Поэтому, если я просматриваю все элементы на eBay, то по одному будет то, что может справиться даже маленький компьютер, но «.ToList ()» наверняка выгонит меня из памяти, независимо от того, насколько большим был мой компьютер. Ни один компьютер сам по себе не может содержать и обрабатывать такое огромное количество данных.
[Править] - Само собой разумеется - это не "или то или это". часто имеет смысл использовать как список, так и IEnumerable в одном классе. Ни один компьютер в мире не может перечислить все простые числа, потому что по определению это потребует бесконечного количества памяти. Но вы можете легко подумать о a,
class PrimeContainer
который содержит aIEnumerable<long> primes
, который по понятным причинам также содержит aSortedList<long> _primes
. все простые числа рассчитаны до сих пор. следующее простое число, которое будет проверено, будет выполнено только с существующими простыми числами (до квадратного корня). Таким образом, вы получаете оба - простые числа по одному (IEnumerable) и хороший список «простых чисел на данный момент», что является довольно хорошим приближением всего (бесконечного) списка.источник