Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# - action on IEnumerable<T>

I have implemented this extension method:

public static IEnumerable<T> DoForEach<T>(this IEnumerable<T> data, Action<T> action)
{
    foreach (T value in data)
    {
        action(value);
        yield return value;
    }
}

when I do

output.DoForEach<string>(c => Console.WriteLine(c));

nothing is written onto console. Any ideas why this isn't working? thanks

like image 551
Miloš Lukačka Avatar asked May 05 '13 20:05

Miloš Lukačka


2 Answers

yield return makes you query lazy, in other words, your method executes only when you start iterating over elements. Lots of LINQ operator are executes if deferred fashion. Next code demonstrates this issue

new[] {1,2}.DoForEach(Console.WriteLine).ToList();

prints:

1
2

while

new[] {1,2}.DoForEach(Console.WriteLine);

prints nothing

to give the full example, examine next snippet:

IEnumerable items = new[] {1,2}.DoForEach(s => Console.WriteLine("inside query:"+s));

foreach (var item in items)
{
    Console.WriteLine ("inside loop:" + item);
}

this will print

inside query:1
inside loop:1
inside query:2
inside loop:2

and it will start to print only on first foreach iteration. No elements being printed when you construct your query

like image 148
Ilya Ivanov Avatar answered Oct 01 '22 08:10

Ilya Ivanov


It's because you're returning an iterator, but not executing it. Given what you have written, you're wanting to perform an action on the list, not get an enumerator back from it, so it looks like you need to have the DoForEach() function return void, and get rid of the yield return in it. This should have your output written to the console.

Edit: Here's a snippet showing what I mean:

    public static void DoForEach<T>(this IEnumerable<T> data, Action<T> action)
    {
        foreach (T value in data)
        {
            action(value);
        }
    }
like image 35
Gjeltema Avatar answered Oct 01 '22 07:10

Gjeltema