Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the yield keyword and LINQ

Tags:

c#

.net

linq

I'm trying to understand the yield keyword better and I think I have a decent enough understanding of it so I ran some tests however I was surpised by the results.

If I run the below code I get the following output which shows that it loops over the whole range not just up to number 4.

    public void DoIt()
    {
        Console.WriteLine("Method Call");
        var results = GetData(Enumerable.Range(1, 10));
        Console.WriteLine("LINQ");
        var filtered = results.Where(x => x == 4);
        Console.WriteLine("Start result loop");
        foreach (var item in filtered)
        {
                Console.WriteLine("Item is " + item);
        }
    }

    private IEnumerable<int> GetData(IEnumerable<int> Input)
    {
        foreach (int item in Input)
        {
            if (item % 2 == 0)
            {
                Console.WriteLine("Found " + item);
                yield return item;
            }
        }
    }

Output:

Method Call
LINQ
Start result loop
Found 2
Found 4
Item is 4
Found 6
Found 8
Found 10

If I run the below code it shows that it only gets to 4 and then stops.

    public void DoIt()
    {
        Console.WriteLine("Method Call");
        var results = GetData(Enumerable.Range(1, 10));
        Console.WriteLine("Start result loop");
        foreach (var item in results)
        {
            if (item == 4)
            {
                Console.WriteLine("Item is " + item);
                break;
            }
        }
    }

    private IEnumerable<int> GetData(IEnumerable<int> Input)
    {
        foreach (int item in Input)
        {
            if (item % 2 == 0)
            {
                Console.WriteLine("Found " + item);
                yield return item;
            }
        }
    }

Output:

Method Call
Start result loop
Found 2
Found 4
Item is 4

I guess I'm not understading something but it looks as if LINQ is doing the opposite of what I expect it to do? I though LINQ used yield and deferred execution as well and I'd expect the results from the second set of code to be the same for the first set of code.

like image 789
Jon Avatar asked Mar 01 '12 11:03

Jon


1 Answers

It does use deferred execution. LINQ Where checks all the elements of the input enumerable, it doesn't stop when it gets to the first element found. That's what First does.

Your first example would return the same as the second example if you changed Where to First, or if you removed the break from the second example.

like image 95
thecoop Avatar answered Sep 27 '22 02:09

thecoop