Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing the Select<> to a Method

Tags:

c#

linq

I have the code

Enumerable.Range(100, 100)
          .Select(x => x / 10)

Is there a way I can pass the line .Select(x => x / 10) to a method. The intention is to pass the results to a method as the select happens. I want to avoid a foreach here.

like image 685
Bob Avatar asked Feb 26 '23 16:02

Bob


1 Answers

You could write your own extension method which performs an action on each item as it passes through:

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

Then depending on whether you wanted to act on the original value or the projected one, you'd write:

Enumerable.Range(100, 100)
          .Select(x => x / 10)
          .WithAction(x => Console.WriteLine(x))

or

Enumerable.Range(100, 100)
          .WithAction(x => Console.WriteLine(x))
          .Select(x => x / 10)

This keeps it independent of the Select itself. If you need it to make use of the projection, you could potentially write something like:

public static IEnumerable<TResult> SelectAndAct<TSource, TResult>
    (this IEnumerable<TSource> source,
     Func<TSource, TResult> projection,
     Action<TSource, TResult> action)
{
    foreach (TSource item in source)
    {
        TResult result = projection(item);
        action(item, result);
        yield return result;
    }
}

Then:

Enumerable.Range(100, 100)
          .SelectAndAct(x => x / 10,
                        (x, y) => Console.WriteLine("Was: {0}; Now: {1}", x, y))

Note that all of this violates the normal intention of LINQ to be side-effect-free. It's not generally a good idea to have side-effects in queries... but of course there are exceptions to every rule :)

like image 78
Jon Skeet Avatar answered Feb 28 '23 07:02

Jon Skeet