Search code examples
c#linqlinqpad

Why do I get a different output from analogous Linq queries?


I am trying the following code in LinqPad 5 (specifically 5.26.01)

     IEnumerable<string> breeds = new List<string>{
        "Fantail",
        "Lahore",
        "Bokhara Trumpeter",
        "Rhine Ringbeater",
        "Birmingham Roller",
        "Pomeranian Pouter",
        "Racing Homer",
        "Archangel"};

    IEnumerable<string> GetAllBreedsContainingLetter_Fluent(IEnumerable<string> breedlist, string letter)
    {
        return breedlist
            .Where(breedname => breedname.Contains(letter.ToUpperInvariant()) || breedname.Contains(letter.ToLowerInvariant()))
            .OrderByDescending(breedname => breedname)
            .Select(breedname => breedname);
    }

    IEnumerable<string> GetAllBreedsContainingLetter_Query(IEnumerable<string> breedlist, string letter)
    {
        return breedlist = from b in breedlist
                            where (b.Contains(letter.ToUpperInvariant()) || b.Contains(letter.ToLowerInvariant()))
                            orderby b descending
                            select b;
    }

    var breedsFluent = GetAllBreedsContainingLetter_Fluent(breeds, "R");
    breedsFluent.Dump();

    var breedsQuery = GetAllBreedsContainingLetter_Query(breeds, "R");
    breedsQuery.Dump();

I think the two functions should be analogous but I noticed something odd about the output in Linqpad. The first .Dump() is identified as an IEnumerable<String>; the second .Dump() identifies as a IOrderedEnumerable<String>.

LinqPadOutput

Is this something about the queries I'm running or is it an artifact of Linqpad? I haven't found anything from Googling.


Solution

  • In query syntax the transformation is such that when you have a trivial projection (projecting an item to itself) it only generates a Select call when that trivial projection is the only operation in the query. Since your query contains other operations, the Select is elided entirely, for performance reasons.

    A proper translation of that query syntax query into method syntax would skip the Select. The way to replicate the behavior using query syntax would require something like a second query, to do the trivial projection.