LINQ эквивалент foreach для IEnumerable <T> - PullRequest
670 голосов
/ 14 октября 2008

Я бы хотел сделать в LINQ следующее, но я не могу понять, как:

IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());

Что такое настоящий синтаксис?

Ответы [ 21 ]

5 голосов
/ 06 января 2014

Как уже указывалось в многочисленных ответах, вы можете легко добавить такой метод расширения самостоятельно. Однако, если вы не хотите этого делать, хотя я не знаю ничего подобного в BCL, в пространстве имен System есть опция, если у вас уже есть ссылка на Reactive Extension (а если нет, то должны иметь):

using System.Reactive.Linq;

items.ToObservable().Subscribe(i => i.DoStuff());

Хотя имена методов немного отличаются, конечный результат - именно то, что вы ищете.

5 голосов
/ 09 июля 2012

Многие упоминали об этом, но я должен был это записать. Разве это не самый понятный / самый читаемый?

IEnumerable<Item> items = GetItems();
foreach (var item in items) item.DoStuff();

Короткий и простой (ст).

3 голосов
/ 02 июня 2011

Теперь у нас есть возможность ...

        ParallelOptions parallelOptions = new ParallelOptions();
        parallelOptions.MaxDegreeOfParallelism = 4;
#if DEBUG
        parallelOptions.MaxDegreeOfParallelism = 1;
#endif
        Parallel.ForEach(bookIdList, parallelOptions, bookID => UpdateStockCount(bookID));

Конечно, это открывает совершенно новую банку с червями.

ps (извините за шрифты, это то, что система решила)

2 голосов
/ 24 февраля 2015

ForEach также может быть Цепной , просто положить обратно на линию свая после действия. остаются в курсе


Employees.ForEach(e=>e.Act_A)
         .ForEach(e=>e.Act_B)
         .ForEach(e=>e.Act_C);

Orders  //just for demo
    .ForEach(o=> o.EmailBuyer() )
    .ForEach(o=> o.ProcessBilling() )
    .ForEach(o=> o.ProcessShipping());


//conditional
Employees
    .ForEach(e=> {  if(e.Salary<1000) e.Raise(0.10);})
    .ForEach(e=> {  if(e.Age   >70  ) e.Retire();});

An Eager версия реализации.

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (T item in enu) action(item);
    return enu; // make action Chainable/Fluent
}

Редактировать: a Ленивая версия использует возврат доходности, как this .

public static IEnumerable<T> ForEachLazy<T>(this IEnumerable<T> enu, Action<T> action)
{
    foreach (var item in enu)
    {
        action(item);
        yield return item;
    }
}

Ленивая версия НУЖДАЕТСЯ в материализации, например, ToList (), иначе ничего не происходит. смотрите ниже отличные комментарии от ToolmakerSteve.

IQueryable<Product> query = Products.Where(...);
query.ForEachLazy(t => t.Price = t.Price + 1.00)
    .ToList(); //without this line, below SubmitChanges() does nothing.
SubmitChanges();

Я храню в своей библиотеке и ForEach (), и ForEachLazy ().

2 голосов
/ 11 сентября 2014

Вдохновленный Джоном Скитом, я расширил его решение следующим образом:

Метод расширения:

public static void Execute<TSource, TKey>(this IEnumerable<TSource> source, Action<TKey> applyBehavior, Func<TSource, TKey> keySelector)
{
    foreach (var item in source)
    {
        var target = keySelector(item);
        applyBehavior(target);
    }
}

Клиент:

var jobs = new List<Job>() 
    { 
        new Job { Id = "XAML Developer" }, 
        new Job { Id = "Assassin" }, 
        new Job { Id = "Narco Trafficker" }
    };

jobs.Execute(ApplyFilter, j => j.Id);

. , .

    public void ApplyFilter(string filterId)
    {
        Debug.WriteLine(filterId);
    }
1 голос
/ 14 марта 2013

Для VB.NET вы должны использовать:

listVariable.ForEach(Sub(i) i.Property = "Value")
1 голос
/ 10 июля 2009

Я с уважением не согласен с тем, что методы расширения ссылок не должны иметь побочных эффектов (не только потому, что их нет, любой делегат может выполнять побочные эффекты).

Обратите внимание на следующее:

   public class Element {}

   public Enum ProcessType
   {
      This = 0, That = 1, SomethingElse = 2
   }

   public class Class1
   {
      private Dictionary<ProcessType, Action<Element>> actions = 
         new Dictionary<ProcessType,Action<Element>>();

      public Class1()
      {
         actions.Add( ProcessType.This, DoThis );
         actions.Add( ProcessType.That, DoThat );
         actions.Add( ProcessType.SomethingElse, DoSomethingElse );
      }

      // Element actions:

      // This example defines 3 distict actions
      // that can be applied to individual elements,
      // But for the sake of the argument, make
      // no assumption about how many distict
      // actions there may, and that there could
      // possibly be many more.

      public void DoThis( Element element )
      {
         // Do something to element
      }

      public void DoThat( Element element )
      {
         // Do something to element
      }

      public void DoSomethingElse( Element element )
      {
         // Do something to element
      }

      public void Apply( ProcessType processType, IEnumerable<Element> elements )
      {
         Action<Element> action = null;
         if( ! actions.TryGetValue( processType, out action ) )
            throw new ArgumentException("processType");
         foreach( element in elements ) 
            action(element);
      }
   }

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

1 голос
/ 19 октября 2018

MoreLinq имеет IEnumerable<T>.ForEach и массу других полезных расширений. Вероятно, не стоит принимать зависимость только для ForEach, но там много полезного.

https://www.nuget.org/packages/morelinq/

https://github.com/morelinq/MoreLINQ

1 голос
/ 18 июля 2010

Еще один ForEach Пример

public static IList<AddressEntry> MapToDomain(IList<AddressModel> addresses)
{
    var workingAddresses = new List<AddressEntry>();

    addresses.Select(a => a).ToList().ForEach(a => workingAddresses.Add(AddressModelMapper.MapToDomain(a)));

    return workingAddresses;
}
1 голос
/ 28 февраля 2019

Чтобы оставаться в курсе, можно использовать такой трюк:

GetItems()
    .Select(i => new Action(i.DoStuf)))
    .Aggregate((a, b) => a + b)
    .Invoke();
...