Существующий метод расширения LINQ, похожий на Parallel.For?[дубликат]
-
11-07-2019 - |
Вопрос
Возможный Дубликат:
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++; });
Решение
Проливая немного больше света на то, почему:
LINQ является функциональным по своей природе.Он используется для запроса данных и возврата результатов.Запрос LINQ не должен изменять состояние приложения (за некоторыми исключениями, такими как кэширование).Поскольку foreach не возвращает никаких результатов, у него не так много применений, которые не предполагают изменения состояния чего-либо, кроме того, что вы ему передаете.И если вам нужен метод расширения Foreach(), он является легко свернуть самостоятельно.
Если, с другой стороны, то, что вы хотите, это принять входные данные и вызвать функцию для каждого элемента, которая возвращает результат, LINQ предоставляет способ с помощью своего метода select .
Например, следующий код вызывает функцию делегирования для каждого элемента в списке, возвращая значение 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();
}
Другие советы
На самом деле, платформа Reactive Extensions Framework от Microsoft Research действительно добавила эту функциональность.В System.Interactive
сборка, в которую они включили Run()
и a Do()
расширения к IEnumerable<T>
.
Делать (действие) выполнит действие над каждым элементом и вернет его обратно.Это полезно, например, для добавления ведения журнала в запрос 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
Запуск (действие) это похоже на цикл 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
Метод ForEach на List<T>
делает это.Вы могли бы обернуть свою коллекцию в список, а затем использовать этот вызов, но на самом деле это не очень приятное занятие.Похоже, тебе придется свернуть свой собственный.
Я слишком сонный, чтобы помнить, но, по сути, метод .ForEach в однопоточном приложении функционально эквивалентен уже существующему оператору foreach.Насколько я понимаю, основное отличие заключается в том, что ForEach можно было бы распараллелить, но это слишком легко привело бы к нежелательному поведению.