Учитывая этот код:
IEnumerable<object> FilteredList()
{
foreach( object item in FullList )
{
if( IsItemInPartialList( item ) )
yield return item;
}
}
Почему я не должен просто кодировать это так:
IEnumerable<object> FilteredList()
{
var list = new List<object>();
foreach( object item in FullList )
{
if( IsItemInPartialList( item ) )
list.Add(item);
}
return list;
}
Я вроде понимаю, что yield
делает ключевое слово. Он сообщает компилятору, что нужно создать определенный тип вещей (итератор). Но зачем это использовать? Помимо того, что это немного меньше кода, что это делает для меня?
FullList.Where(IsItemInPartialList)
:)Ответы:
Использование
yield
делает коллекцию ленивой.Допустим, вам просто нужны первые пять предметов. Ваш путь, я должен пройтись по всему списку, чтобы получить первые пять предметов. С помощью
yield
я только перебираю первые пять пунктов.источник
FullList.Where(IsItemInPartialList)
будет столь же ленивым. Только для этого требуется гораздо меньше сгенерированного компилятором пользовательского кода. И меньше времени разработчиков на написание и сопровождение. (Конечно, это был только этот пример)yield return
) везде, где это было возможно.Преимущество блоков итераторов в том, что они работают лениво. Таким образом, вы можете написать метод фильтрации следующим образом:
Это позволит вам фильтровать поток сколько угодно, никогда не буферизуя более одного элемента за раз. Например, если вам нужно только первое значение из возвращенной последовательности, зачем вам копировать все в новый список?
В качестве другого примера, вы можете легко создать бесконечный поток, используя блоки итераторов. Например, вот последовательность случайных чисел:
Как бы вы сохранили бесконечную последовательность в списке?
В моей серии блогов Edulinq приведен пример реализации LINQ to Objects, в которой интенсивно используются блоки итераторов. LINQ, в сущности, ленив, где это может быть - и размещение вещей в списке просто не работает таким образом.
источник
RandomSequence
или нет. Для меня IEnumerable означает - в первую очередь - то, что я могу повторять с помощью foreach, но это, очевидно, привело бы к бесконечному циклу. Я бы посчитал это довольно опасным злоупотреблением концепцией IEnumerable, но YMMV.IEnumerable<BigInteger>
Например, вы можете легко создать представляющую последовательность Фибоначчи. Вы можете использоватьforeach
с этим, но ничто неIEnumerable<T>
гарантирует, что это будет конечно.С помощью кода «list» вам необходимо обработать полный список, прежде чем вы сможете передать его на следующий шаг. Версия «yield» передает обработанный элемент немедленно на следующий шаг. Если этот «следующий шаг» содержит «.Take (10)», то версия «yield» обработает только первые 10 элементов и забудет обо всех остальных. Код "list" обработал бы все.
Это означает, что вы видите наибольшую разницу, когда вам нужно много обработать и / или иметь длинные списки элементов для обработки.
источник
Вы можете использовать
yield
для возврата товаров, которых нет в списке. Вот небольшой пример, который может бесконечно перебирать список, пока не будет отменен.Это пишет
...и т.д. на консоль, пока не отменено.
источник
Когда приведенный выше код используется для циклического обхода FilteredList () и в предположении, что item.Name == "James" будет удовлетворен для 2-го элемента в списке, использование метода
yield
даст два результата. Это ленивое поведение.Где, как метод, использующий список, добавит все n объектов в список и передаст полный список вызывающему методу.
Это именно тот случай, когда можно выделить разницу между IEnumerable и IList.
источник
Лучший пример из реальной жизни, который я видел для использования, -
yield
это вычисление последовательности Фибоначчи.Рассмотрим следующий код:
Это вернет:
Это хорошо, потому что позволяет быстро и легко вычислять бесконечные ряды, давая вам возможность использовать расширения Linq и запрашивать только то, что вам нужно.
источник
Иногда это полезно, иногда нет. Если весь набор данных должен быть проверен и возвращен, то не будет никакой пользы в использовании yield, потому что все, что он делал, это вводило накладные расходы.
Когда yield действительно сияет, это когда возвращается только частичный набор. Я думаю, что лучший пример - сортировка. Предположим, у вас есть список объектов, содержащих дату и сумму в долларах за этот год, и вы хотели бы увидеть первые несколько (5) записей года.
Для этого список должен быть отсортирован по возрастанию по дате, а затем взяты первые 5. Если бы это было сделано без выхода, весь список пришлось бы отсортировать, чтобы убедиться, что последние две даты были в порядке.
Однако с выходом, после того, как первые 5 элементов были установлены, сортировка прекращается, и результаты доступны. Это может сэкономить большое количество времени.
источник
Заявление о возврате доходности позволяет вам возвращать только один товар за раз. Вы собираете все элементы в списке и снова возвращаете этот список, что приводит к нехватке памяти.
источник