简体   繁体   中英

Linq query syntax and extension methods

I usually prefer the extension methods, because they i find them easier to read, but after seeing the answer by Erno to this question I was wondering how the minimum query would look with only extension methods used?

And more generally, are there queries that you can create in one form but not the other, or are both approaches equivalent?

Taken from ILSpy:

This

var minimum = (from p1 in differenceList
                from p2 in differenceList
                let distance = Math.Abs(p1.X - p2.X)
                where !object.ReferenceEquals(p1, p2)
                orderby distance
                select new { Point1 = p1, Point2 = p2, Distance = distance }).First();

is (with a little cleaning) and with comments

var minimum = differenceList
    // The two from
    .SelectMany(
        p1 => differenceList, 
        (p1, p2) =>
        new {
            p1 = p1, 
            p2 = p2
        })
    // The let
    .Select(q => 
        new{
            q = q, 
            distance = Math.Abs(q.p1.X - q.p2.X)
        })
    // The where
    .Where(r => !object.ReferenceEquals(r.q.p1, r.q.p2))
    // The orderby
    .OrderBy(r => r.distance)
    // The final select
    .Select(r => new
    {
        Point1 = r.q.p1, 
        Point2 = r.q.p2, 
        Distance = r.distance
    })
    // The First
    .First();

I have to tell the truth, the only thing I didn't know how to do "by hand" was the two from . I suspected it was a SelectMany , but it would have taken me at least 30 minutes to crack it. If you are interested, in ILSpy Options->Decompiler and deactivate "Decompile query expressions.

There's nothing you can do in query expressions which can't be done without query expressions - query expressions are just translated into non-query-expression code anyway. There are plenty of queries that can't be written in query expressions though... for example, anything using the Select overload which provides the index as well:

var foo = bar.Select((value, index) => new { value, index });

... and of course, all the many operators which aren't supported by query expressions at all ( First etc).

The "minimum" query would use SelectMany for the second from clause, Select for the let clause (introducing a new transparent identifier), Where for the where clause, and Select for the select clause.

Some querys can only be written using the extension method syntax(in particular there are extension methods the query syntax doesn't support). The extension method syntax supports everything the query syntax supports, since the query syntax gets compiled into the very same extension methods.

On the other hand the query syntax has a few features which are a bit more verbose in the extension method syntax ( let and certain join s).

join can be replaced by SelectMany and let with a Select that introduces a anonymous type that includes both the actual variable in the query and the variable introduced in the let clause.

A clean version in extension method syntax would look like this:

differenceList
    .SelectMany(p1=>differencelist,(p1,p2) => new {Point1 = p1,Point2 = p2,
           Distance=Math.Abs(q.p1.X - q.p2.X)})
    .Where(e=>!object.ReferenceEquals(e.p1,e.p2))
    .OrderBy(e=>e.Distance)
    .First();

Every Linq expression can be expressed using extension methods. The compiler translates Linq into them anyway. On the other hand, not every extension method can be expressed in Linq syntax.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM