Я хотел бы сделать эквивалент следующего в LINQ, но я не могу понять, как:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
Какой реальный синтаксис?
linq
foreach
ienumerable
tags2k
источник
источник
ForEach()
.ForEach
расширение .foreach (var i in items) i.Dostuff();
Ответы:
Для ForEach нет расширения
IEnumerable
; только дляList<T>
. Так что вы могли бы сделатьВ качестве альтернативы, напишите свой собственный метод расширения ForEach:
источник
IENumerable<T>
в методе расширения. Как:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Фредрик предоставил исправление, но, возможно, стоит подумать, почему это не входит в рамки для начала. Я считаю, что идея заключается в том, чтобы операторы запросов LINQ не имели побочных эффектов и соответствовали разумно функциональному взгляду на мир. Очевидно, что ForEach с точностью до наоборот - конструкция, основанная исключительно на побочных эффектах.
Нельзя сказать, что это плохая вещь - просто думать о философских причинах решения.
источник
Seq.iter
ничего не возвращает, не говоря уже о новом seq с побочными эффектами. Это действительно только побочные эффекты. Вы можете подуматьSeq.map
, потому чтоSeq.iter
это точно эквивалентноForEach
методу расширения наIEnumerabe<_>
.Обновление от 17.07.2012: по-видимому, начиная с C # 5.0, поведение,
foreach
описанное ниже, было изменено, и « использованиеforeach
переменной итерации во вложенном лямбда-выражении больше не приводит к неожиданным результатам». Этот ответ не относится к C # ≥ 5.0 ,@ Джон Скит и все, кто предпочитает ключевое слово foreach.
Проблема с «foreach» в C # до 5.0 заключается в том, что он не согласуется с тем, как эквивалент «для понимания» работает на других языках, и с тем, как я ожидаю, что он будет работать (личное мнение изложено здесь только потому, что другие упоминали их мнение относительно читабельности). См. Все вопросы, касающиеся « Доступ к измененному закрытию », а также « Закрытие по переменной цикла, считающейся вредной ». Это только «вредно» из-за способа, которым «foreach» реализован в C #.
Возьмите следующие примеры, используя функционально эквивалентный метод расширения, описанный в ответе @Fredrik Kalseth.
Извиняюсь за чрезмерно надуманный пример. Я использую только Observable, потому что делать что-то подобное не так уж и сложно. Очевидно, есть лучшие способы создать эту наблюдаемую, я только пытаюсь продемонстрировать точку. Обычно код, подписанный на наблюдаемое, выполняется асинхронно и, возможно, в другом потоке. Если использовать «foreach», это может привести к очень странным и потенциально недетерминированным результатам.
Следующий тест с использованием метода расширения «ForEach»:
Следующие ошибки с ошибкой:
Ожидаемое: эквивалентно <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> Но было: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9>
источник
Вы можете использовать
FirstOrDefault()
расширение, которое доступно дляIEnumerable<T>
. Возвращаясьfalse
из предиката, он будет запускаться для каждого элемента, но ему будет все равно, что он не найдет совпадения. Это позволит избежатьToList()
накладных расходов.источник
foreach(Item i in GetItems()) { i.DoStuff();}
вас взяли больше персонажей и сделали это крайне запутаннымitems.All(i => { i.DoStuff(); return true; }
Я взял метод Фредрика и изменил тип возвращаемого значения.
Таким образом, метод поддерживает отложенное выполнение, как и другие методы LINQ.
РЕДАКТИРОВАТЬ: Если это не было ясно, любое использование этого метода должно заканчиваться ToList () или любым другим способом, чтобы заставить метод работать над полным перечислимым. В противном случае действие не будет выполнено!
И вот тест, чтобы помочь увидеть это:
Если вы в конце удалите ToList () , вы увидите, что тест не пройден, так как StringBuilder содержит пустую строку. Это потому, что ни один метод не заставил ForEach перечислять.
источник
ForEach
интересна, однако она не соответствует поведениюList.ForEach
, сигнатура которой естьpublic void ForEach(Action<T> action)
. Это также не соответствует поведениюObservable.ForEach
расширенияIObservable<T>
, подпись которого естьpublic static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
. FWIW,ForEach
эквивалент в коллекциях Scala, даже ленивых, также имеет тип возвращаемого значения, эквивалентный void в C #.Select
сToList
. ЦельForEach
состоит в том, чтобы не звонитьToList
. Это должно быть выполнено немедленно.Держите ваши побочные эффекты от моего IEnumerable
Как отмечают другие здесь и за рубежом, LINQ и
IEnumerable
методы, как ожидается, будут свободны от побочных эффектов.Вы действительно хотите «сделать что-то» с каждым элементом в IEnumerable? Тогда
foreach
это лучший выбор. Люди не удивляются, когда здесь происходят побочные эффекты.Бьюсь об заклад, вы не хотите побочный эффект
Однако по моему опыту побочные эффекты обычно не требуются. Чаще всего существует простой запрос LINQ, ожидающий своего открытия, сопровождаемый ответом StackOverflow.com от Jon Skeet, Eric Lippert или Marc Gravell, объясняющих, как делать то, что вы хотите!
Некоторые примеры
Если вы на самом деле просто агрегируете (накапливаете) какое-то значение, вам следует рассмотреть
Aggregate
метод расширения.Возможно, вы хотите создать новое
IEnumerable
из существующих значений.Или, может быть, вы хотите создать справочную таблицу:
Список (каламбур не совсем предназначен) возможностей можно продолжать и продолжать.
источник
Если вы хотите выступить в роли списков, вам нужно сдать каждый предмет.
источник
Существует экспериментальный выпуск Microsoft Interactive Extensions для LINQ (также на NuGet , см . Профиль RxTeams для получения дополнительных ссылок). 9 видео канала объясняет это хорошо.
Его документы предоставляются только в формате XML. Я запустил эту документацию в Sandcastle, чтобы она была в более читаемом формате. Распакуйте архив документов и найдите файл index.html .
Среди многих других полезностей, он обеспечивает ожидаемую реализацию ForEach. Это позволяет вам писать код так:
источник
Согласно PLINQ (доступно с версии .Net 4.0), вы можете сделать
сделать параллельный цикл foreach на IEnumerable.
источник
Цель ForEach - вызывать побочные эффекты. IEnumerable для ленивого перечисления множества.
Это концептуальное различие весьма заметно, если учесть его.
SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));
Это не будет выполняться до тех пор, пока вы не сделаете "count" или "ToList ()" или что-то в этом роде. Это явно не то, что выражается.
Вы должны использовать расширения IEnumerable для настройки цепочек итераций, определения контента по их соответствующим источникам и условиям. Деревья выражения являются мощными и эффективными, но вы должны научиться ценить их природу. И не только для программирования вокруг них, чтобы сохранить несколько символов, перекрывающих ленивую оценку.
источник
Многие упоминали об этом, но я должен был это записать. Разве это не самый понятный / самый читаемый?
Коротко и просто (ст).
источник
GetItems()
метод возвращает.foreach (var item in GetItems()) item.DoStuff();
это просто красота.Теперь у нас есть возможность ...
Конечно, это открывает новую банку с червями.
ps (извините за шрифты, это то, что система решила)
источник
Как уже указывалось в многочисленных ответах, вы можете легко добавить такой метод расширения самостоятельно. Однако, если вы не хотите этого делать, хотя я не знаю ничего подобного в BCL, в
System
пространстве имен все еще есть опция , если у вас уже есть ссылка на Reactive Extension (и если вы этого не делаете , Вы должны иметь):Хотя имена методов немного отличаются, конечный результат - именно то, что вы ищете.
источник
ForEach также может быть Chained , просто положить обратно в pileline после действия. оставаться в курсе
Нетерпеливый версия реализации.
Edit: Ленивая версия использует возврат доходности, как это .
Ленивая версия должна быть материализована, например ToList (), иначе ничего не происходит. см. ниже отличные комментарии от ToolmakerSteve.
Я храню и ForEach (), и ForEachLazy () в моей библиотеке.
источник
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
? Единственный явный цикл. Я думаю, было ли важно сделать все действия action1 ДО того, как начать делать action2.ProcessShipping()
? Вы отправляете электронное письмо покупателю, снимаете деньги с его кредитной карты, но никогда не отправляете ему его вещи? Конечно, просят проблемы.Эта абстракция "функционального подхода" протекает очень долго. Ничто на уровне языка не предотвращает побочные эффекты. Пока вы можете заставить его вызывать лямбда / делегат для каждого элемента в контейнере - вы получите поведение «ForEach».
Вот, например, один из способов слияния srcDictionary в destDictionary (если ключ уже существует - перезаписывает)
это взлом, и его не следует использовать ни в одном рабочем коде.
источник
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
? Если нет в рабочем коде, где и почему вы должны когда-либо использовать это?Вдохновленный Джоном Скитом, я расширил его решение следующим:
Метод продления:
Клиент:
, , ,
источник
У MoreLinq есть
IEnumerable<T>.ForEach
и множество других полезных расширений. Вероятно, не стоит брать зависимость только дляForEach
, но там много полезного.https://www.nuget.org/packages/morelinq/
https://github.com/morelinq/MoreLINQ
источник
Я с уважением не согласен с тем, что методы расширения ссылок не должны иметь побочных эффектов (не только потому, что это не так, любой делегат может выполнять побочные эффекты).
Учтите следующее:
То, что показано в примере, на самом деле является своего рода поздним связыванием, которое позволяет вызвать одно из многих возможных действий, имеющих побочные эффекты на последовательности элементов, без необходимости писать большую конструкцию переключателя для декодирования значения, которое определяет действие, и преобразования. это в соответствующий метод.
источник
Чтобы оставаться в курсе, можно использовать такой трюк:
источник
Для VB.NET вы должны использовать:
источник
List
илиIList
. Для общегоIEnumerable
, напишите VB эквивалент принятого ответа метода расширения ForEach.Еще один
ForEach
примеристочник