Существующий метод расширения 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 может быть парализован, но это слишком легко приведет к нежелательному поведению.