Existing LINQ extension method similar to Parallel

2019-02-03 07:09发布

问题:

Possible Duplicate:
LINQ equivalent of foreach for IEnumerable<T>

The linq extension methods for ienumerable are very handy ... but not that useful if all you want to do is apply some computation to each item in the enumeration without returning anything. So I was wondering if perhaps I was just missing the right method, or if it truly doesn't exist as I'd rather use a built-in version if it's available ... but I haven't found one :-)

I could have sworn there was a .ForEach method somewhere, but I have yet to find it. In the meantime, I did write my own version in case it's useful for anyone else:

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);
        }
    }
}

usage is:

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

回答1:

Shedding a little more light on why:

LINQ is functional in nature. It is used to query data and return results. A LINQ query shouldn't be altering the state of the application (with some exceptions like caching). Because foreach doesn't return any results, it doesn't have many uses that don't involve altering the state of something besides what you are passing in to it. And if you need a Foreach() extension method, it is easy to roll your own.

If, on the other hand, what you want is to take input and call a function on each item that returns a result, LINQ provides a way through its select method.

For example, the following code calls a function delegate on every item in a list, returning true if that item is positive:

    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:

Actually, the Reactive Extensions framework from Microsoft Research did add this functionality. In the System.Interactive assembly they've included a Run() and a Do() extensions to IEnumerable<T>.

Do(action) will execute the action on each element and yield it back. This is useful for adding logging to a linq query for example:

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));

This will result in:

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) is like a foreach loop, which means its folding the sequence which executing the action.

You can read more about it here: http://community.bartdesmet.net/blogs/bart/archive/2009/12/26/more-linq-with-system-interactive-the-ultimate-imperative.aspx

The Rx framework can be found here: http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx



回答3:

The ForEach method on List<T> does this. You could wrap your collection in a list and then use that call, but that's not really a nice thing to do. Looks like you'll have to roll your own.



回答4:

Already discussed here and there.

Im too drowsy to remember but, basically, a .ForEach method in a single thread application is functionally equivalent the already existing foreach statement. From what I understand, the main difference is that a ForEach could be parallized but that would introduce unwanted behaviours too easily.