Почему в IEnumerable отсутствует метод расширения ForEach? - PullRequest
341 голосов
/ 19 сентября 2008

Вдохновлен другим вопросом о недостающей функции Zip:

Почему в классе Enumerable нет метода расширения ForEach? Или где угодно? Единственный класс, который получает метод ForEach - это List<>. Есть ли причина, по которой он отсутствует (производительность)?

Ответы [ 21 ]

4 голосов
/ 01 ноября 2008

@ Coincoin

Реальная сила метода расширения foreach заключается в возможности многократного использования Action<> без добавления ненужных методов в ваш код. Скажем, у вас есть 10 списков, и вы хотите выполнять с ними одинаковую логику, а соответствующая функция не вписывается в ваш класс и не используется повторно. Вместо десяти циклов for или универсальной функции, которая, очевидно, не является вспомогательным, вы можете хранить всю свою логику в одном месте (Action<>. Таким образом, десятки строк заменяются на

Action<blah,blah> f = { foo };

List1.ForEach(p => f(p))
List2.ForEach(p => f(p))

и т.д ...

Логика в одном месте, и вы не загрязнили свой класс.

2 голосов
/ 11 ноября 2009

В 3.5 все методы расширения, добавленные в IEnumerable, предназначены для поддержки LINQ (обратите внимание, что они определены в классе System.Linq.Enumerable). В этом посте я объясню, почему foreach не принадлежит LINQ: Существующий метод расширения LINQ похож на Parallel.For?

2 голосов
/ 02 февраля 2009

Я написал в блоге об этом: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

Вы можете проголосовать здесь, если хотите увидеть этот метод в .NET 4.0: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093

2 голосов
/ 19 сентября 2008

Вы можете использовать select, если хотите что-то вернуть. Если вы этого не сделаете, вы можете сначала использовать ToList, потому что вы, вероятно, не хотите ничего изменять в коллекции.

2 голосов
/ 19 сентября 2008

Это я или Список . Поскольку Линк почти устарел. Первоначально был

foreach(X x in Y) 

, где Y просто должен был быть IEnumerable (Pre 2.0) и реализовывать GetEnumerator (). Если вы посмотрите на сгенерированный MSIL, вы увидите, что он точно такой же, как

IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
    int i = enumerator.Current;

    Console.WriteLine(i);
}

(см. http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx для MSIL)

Затем в DotNet2.0 появились Generics и список. Foreach всегда чувствовал, что я являюсь реализацией шаблона Vistor (см. Шаблоны проектирования от Gamma, Helm, Johnson, Vlissides).

Теперь, конечно, в 3.5 мы можем вместо этого использовать лямбду для того же эффекта, например, попробуйте http://dotnet -developments.blogs.techtarget.com / 2008/09/02 / итераторы лямбда-и-LINQ-о-мой /

2 голосов
/ 19 сентября 2008

Если у вас есть F # (который будет в следующей версии .NET), вы можете использовать

Seq.iter doSomething myIEnumerable

2 голосов
/ 14 октября 2018

Частично это потому, что разработчики языка не согласны с этим с философской точки зрения.

  • Отсутствие (и тестирование ...) функции - это меньше работы, чем наличие функции.
  • Это на самом деле не короче (в некоторых случаях это происходит, но это не будет основным использованием).
  • Его цель - побочные эффекты, о которых не говорит linq.
  • Почему есть другой способ сделать то же самое, что и функция, которую мы уже получили? (ключевое слово foreach)

https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/

2 голосов
/ 19 сентября 2008

Большинство методов расширения LINQ возвращают результаты. ForEach не вписывается в этот шаблон, поскольку он ничего не возвращает.

2 голосов
/ 17 февраля 2016

Я хотел бы остановиться на Ответ Аку .

Если вы хотите вызвать метод с единственной целью его побочного эффекта, не повторяя сначала все перечисляемое, вы можете использовать это:

private static IEnumerable<T> ForEach<T>(IEnumerable<T> xs, Action<T> f) {
    foreach (var x in xs) {
        f(x); yield return x;
    }
}
1 голос
/ 12 июля 2016

Чтобы использовать Foreach, ваш список должен быть загружен в первичную память. Но из-за отложенной загрузки IEnumerable они не предоставляют ForEach в IEnumerable.

Однако, загружая (используя ToList ()), вы можете загрузить свой список в память и использовать ForEach.

...