Jon
Jon

Reputation: 40062

Understanding the yield keyword and 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.

Upvotes: 5

Views: 345

Answers (2)

thecoop
thecoop

Reputation: 46158

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.

Upvotes: 12

Mithrandir
Mithrandir

Reputation: 25397

I think you got your basic logic wrong, not LINQ. Your first example has to iterate over the whole range, because the where-condition has to find all the values that are equal to 4, not just the first value, that is equal to 4.

Upvotes: 2

Related Questions