Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select method is not called using LinQ query syntax

Tags:

c#

linq

I want to enable LinQ query syntax over my classes. I think query syntax is translated to method syntax, for example:

var query = from p in new Class1<Product>()
        where p.Id == "1000"
        select p

is translated to:

var query = new Class1<Product>().Where(p => p.Id == "1000").Select(p => p);

Then I have implemented my Class1 as:

public class Class1<T>
{
    public Class1<T> Where(Expression<Func<T, bool>> expression)
    {
        return this;
    }
    public Class1<T> Select<TResult>(Func<T, TResult> expression)
    {
        return this;
    }
}

And I have tested it with this code:

static void Main(string[] args)
{
    var query = from p in new Class1<Product>()
                where p.Id == "1000"
                select p;
}

Then I have noticed that Select method is not called, however if I remove where clausule from LinQ Select is called:

static void Main(string[] args)
{
    var query = from p in new Class1<Product>()
                // where p.Id == "1000" -> commenting that Select method is called
                select p;
}

Someone knows why?

Here a fiddle where you can test it: https://dotnetfiddle.net/JgxKG9

like image 247
Javier Ros Avatar asked Nov 30 '22 09:11

Javier Ros


2 Answers

Someone knows why?

Yes, because that's what the language specification says to do. The query expression translation is all in section 7.16.2 of the C# 5 specification.

Section 7.16.2.5 explains why your initial example is incorrect - Select won't be called:

A query expression of the form

from x in e select v

is translated into

( e ) . Select ( x => v )

except when v is the identifier x, the translation is simply

( e )

For example

from c in customers.Where(c => c.City == “London”)
select c

is simply translated into

customers.Where(c => c.City == “London”)

However, that isn't the case for degenerate query expressions which are covered in 7.16.2.3 - which explains what happens when you remove your where clause:

A query expression of the form

from x in e select x

is translated into

( e ) . Select ( x => x )

The example

from c in customers
select c

Is translated into

customers.Select(c => c)

A degenerate query expression is one that trivially selects the elements of the source. A later phase of the translation removes degenerate queries introduced by other translation steps by replacing them with their source. It is important however to ensure that the result of a query expression is never the source object itself, as that would reveal the type and identity of the source to the client of the query. Therefore this step protects degenerate queries written directly in source code by explicitly calling Select on the source. It is then up to the implementers of Select and other query operators to ensure that these methods never return the source object itself.

like image 180
Jon Skeet Avatar answered Dec 10 '22 06:12

Jon Skeet


Your understanding is little incorrect, the following query :

var query = from p in new Class1<Product>()
        where p.Id == "1000"
        select p

will translate to :

var query = new Class1<Product>().Where(p => p.Id == "1000");

and when you are removing the where part:

var query = from p in new Class1<Product>()
            select p;

now it will be translated to something like:

var query = new Class1<Product>().Select(p=>p);
like image 27
Ehsan Sajjad Avatar answered Dec 10 '22 04:12

Ehsan Sajjad