Существующий метод расширения LINQ аналогичен Parallel.For?

Возможный дубликат:
LINQ эквивалент foreach для IEnumerable <T>

Методы расширения linq для ienumerable очень удобны... но не так полезны, если все, что вы хотите сделать, это применить некоторые вычисления к каждому элементу перечисления, не возвращая ничего. Поэтому мне было интересно, возможно ли, что я просто отсутствовал в правильном методе, или если это действительно не существует, поскольку я бы предпочел использовать встроенную версию, если она доступна... но я не нашел ее: -)

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

using System.Collections;
using System.Collections.Generic;

public delegate void Function<T>(T item);
public delegate void Function(object item);

public static class EnumerableExtensions
{
    public static void For(this IEnumerable enumerable, Function func)
    {
        foreach (object item in enumerable)
        {
            func(item);
        }
    }

    public static void For<T>(this IEnumerable<T> enumerable, Function<T> func)
    {
        foreach (T item in enumerable)
        {
            func(item);
        }
    }
}

используется:

myEnumerable.For<MyClass>(delegate(MyClass item) { item.Count++; });

Ответы

Ответ 1

Пролить немного больше света на почему:

LINQ функциональный по своей природе. Он используется для запроса данных и возврата результатов. Запрос LINQ не должен изменять состояние приложения (с некоторыми исключениями, такими как кеширование). Поскольку foreach не возвращает никаких результатов, он не имеет много применений, которые не связаны с изменением состояния чего-либо, кроме того, что вы ему передаете. И если вам нужен метод расширения Foreach(), он легко сворачивает ваш собственный.

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

Например, следующий код вызывает делегат функции для каждого элемента в списке, возвращая true, если этот элемент положителен:

    static void Main(string[] args)
    {
        IEnumerable<int> list = new List<int>() { -5, 3, -2, 1, 2, -7 };
        IEnumerable<bool> isPositiveList = list.Select<int, bool>(i => i > 0);

        foreach (bool isPositive in isPositiveList)
        {
            Console.WriteLine(isPositive);
        }

        Console.ReadKey();        
    }

Ответ 2

Собственно, инфраструктура Reactive Extensions от Microsoft Research добавила эту функциональность. В сборке System.Interactive они добавили расширения Run() и Do() к IEnumerable<T>.

Do (action) выполнит действие над каждым элементом и вернет его. Это полезно для добавления журнала в запрос linq, например:

var res = GetRandomNumbers(100).Take(10)
      .Do(x => Console.WriteLine("Source  -> {0}", x))
      .Where(x => x % 2 == 0)
      .Do(x => Console.WriteLine("Where   -> {0}", x))
      .OrderBy(x => x)
      .Do(x => Console.WriteLine("OrderBy -> {0}", x))
      .Select(x => x + 1)
      .Do(x => Console.WriteLine("Select  -> {0}", x));

Это приведет к:

Source  -> 96 
Where   -> 96 
Source  -> 25 
Source  -> 8 
Where   -> 8 
Source  -> 79 
Source  -> 25 
Source  -> 3 
Source  -> 36 
Where   -> 36 
Source  -> 51 
Source  -> 53 
Source  -> 81 
OrderBy -> 8 
Select  -> 9 
9 
OrderBy -> 36 
Select  -> 37 
37 
OrderBy -> 96 
Select  -> 97 
97

Run (action) - это как цикл foreach, что означает его свертывание последовательности, выполняющей действие.

Подробнее об этом можно прочитать здесь: http://community.bartdesmet.net/blogs/bart/archive/2009/12/26/more-linq-with-system-interactive-the-ultimate-imperative.aspx

Рамку Rx можно найти здесь: http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

Ответ 3

Метод ForEach на List<T> делает это. Вы можете обернуть свою коллекцию в список, а затем использовать этот вызов, но это не очень приятно. Похоже, вам придется сворачивать самостоятельно.

Ответ 4

Уже обсуждалось here и там.

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