Take the 2-minute tour ×

I have come to use LINQ in my every day programming a lot. In fact, I rarely, if ever, use an explicit loop. I have, however, found that I don't use the SQL like syntax anymore. I just use the extension functions. So rather then saying:

from x in y select datatransform where filter 

I use:

x.Where(c => filter).Select(c => datatransform)

Which style of LINQ do you prefer and what are others on your team are comfortable with?

share|improve this question
May be worth noting that the official MS stance is that the query syntax is preferable. –  R0MANARMY Jun 10 '11 at 16:49
Ultimately it doesn't matter. What matters is that the code is understandable. One form may be better in one case, the other in a different case. So use which ever is appropriate at the time. –  ChrisF Jun 11 '11 at 19:38
I believe your second example is called lambda syntax, which what I use 95% of the time. The other 5% I use the query syntax which is when I'm doing joins, i'm attempting to transition to lambda syntax joins but like others have pointed out it gets messy. –  The Muffin Man Jun 11 '11 at 22:07
add comment

closed as not constructive by Jim G., gnat, Walter, Mark Trapp, Matthieu Sep 6 '12 at 12:17


9 Answers

up vote 18 down vote accepted

I find it unfortunate that Microsoft's stance per MSDN documentation is that the query syntax is preferable, because I never use it, but I use LINQ method syntax all the time. I love being able to fire off one-liner queries to my heart's content. Compare:

var products = from p in Products
               where p.StockOnHand == 0
               select p;


var products = Products.Where(p => p.StockOnHand == 0);

Quicker, fewer lines, and to my eyes looks cleaner. Query syntax doesn't support all of the standard LINQ operators either. An example query I recently did looked something like this:

var itemInfo = InventoryItems
    .Where(r => r.ItemInfo is GeneralMerchInfo)
    .Select(r => r.ItemInfo)
    .FirstOrDefault(r => r.Xref == xref);

To my knowledge, to replicate this query using query syntax (to the extent possible) it would look like this:

var itemInfo = (from r in InventoryItems
                where r.ItemInfo is GeneralMerchInfo
                select r.ItemInfo)
                .FirstOrDefault(r => r.Xref == xref);

Doesn't look more readable to me, and you'd need to know how to use method syntax anyway. Personally I'm really enamored of the declarative style LINQ makes possible and use it in any situation where it's at all possible - perhaps sometimes to my detriment. Case in point, with method syntax I can do something like this:

// projects an InventoryItem collection with total stock on hand for each GSItem
inventoryItems = repository.GSItems
    .Select(gsItem => new InventoryItem() {
        GSItem = gsItem,
        StockOnHand = repository.InventoryItems
            .Where(inventoryItem => inventoryItem.GSItem.GSNumber == gsItem.GSNumber)
            .Sum(r => r.StockOnHand)

I'd imagine the above code would be difficult to understand for someone coming into the project without good documentation, and if they don't have a solid background in LINQ they might not understand it anyway. Still, method syntax exposes some pretty powerful capability, to quickly (in terms of lines of code) project a query to get aggregate information about multiple collections that would otherwise take a lot of tedious foreach looping. In a case like this, method syntax is ultra compact for what you get out of it. Trying to do this with with query syntax might get unwieldy rather quickly.

share|improve this answer
The cast you can do inside the select but unfortunately you can't specify to take the top X records without resorting to using the LINQ methods. This is especially annoying in places where you know you only need a single record and have to put all the query in brackets. –  Ziv Jun 12 '11 at 12:33
Just for the record you can do Select(x => x.ItemInfo).OfType<GeneralMerchInfo>() instead of the Where().Select().Cast<>(), which I believe is faster (big O of 2n instead of n*2m I think). But you're totally right, the lambda syntax is much better from a readability standpoint. –  Ed Woodcock Jun 16 '11 at 19:12
add comment

I find the functional syntax more pleasing on the eye. The only exception is if I need to join more than two sets. The Join() gets crazy very quickly.

share|improve this answer
Agreed...I much more prefer the look and readability from the extension methods except (as pointed out) when joining. Component vendors (e.g. Telerik) use the extension methods a great deal. The example I'm thinking about is their Rad Controls in ASP.NET MVC. You need to be very proficient using extension methods to use/read those. –  Catchops Jun 10 '11 at 16:03
Came to say this. I usually use lambdas unless there's a join involved. Once there's a join, the LINQ syntax tends to be more readable. –  Sean Sep 4 '12 at 13:31
add comment

My advice is to use the query comprehension syntax when the whole expression can be done in the comprehension syntax. That is, I would prefer:

var query = from c in customers orderby c.Name select c.Address;


var query = customers.OrderBy(c=>c.Name).Select(c=>c.Address);

But I would prefer

int count = customers.Where(c=>c.City == "London").Count();


int count = (from c in customers where c.City == "London" select c).Count();

I wish we had come up with some syntax that made it nicer to mix the two. Something like:

int count = from c in customers 
            where c.City == "London" 
            select c 
            continue with Count();

But sadly we did not.

But basically, it's a matter of preference. Do the one that looks better to you and your coworkers.

share|improve this answer
Alternatively you could consider separating a comprehension from other LINQ operator calls via an "introduce explaining variable" refactoring. for example, var londonCustomers = from c in ...; int count = londonCustomers.Count(); –  devgeezer Sep 4 '12 at 14:29
add comment

Is it ever too late to add another answer?

I've written a ton of LINQ-to-objects code and I contend that at least in that domain that it's good to understand both syntaxes in order to use whichever makes for simpler code -- which isn't always dot-syntax.

Of course there are times when dot-syntax IS the way to go - others have provided several of these cases; however, I think comprehensions have been short-changed - given a bad rap, if you will. So I'll provide a sample where I believe comprehensions are useful.

Here's a solution to a digit substitution puzzle: (solution written using LINQPad, but can stand-alone in a console app)

// NO
// NO
// NO
// OK

var solutions =
    from O in Enumerable.Range(1, 8) // 1-9
    from N in Enumerable.Range(1, 8) // 1-9
    where O != N
    let NO = 10 * N + O
    let product = 4 * NO
    where product < 100
    let K = product % 10
    where K != O && K != N && product / 10 == O
    select new { N, O, K };

foreach(var i in solutions)
    Console.WriteLine("N = {0}, O = {1}, K = {2}", i.N, i.O, i.K);

//Console.WriteLine("\nsolution expression tree\n" + solutions.Expression);

...which outputs:

N = 1, O = 6, K = 4

Not too bad, the logic flows linearly and we can see that it comes up with a single correct solution. This puzzle is easy enough to solve by hand: reasoning that 3 > N > 0, and O > 4 * N implies 8 >= O >= 4. That means there's a maximum of 10 cases to test by hand (2 for N -by- 5 for O). I've strayed enough - this puzzle is offered for LINQ illustration purposes.

Compiler Transformations

There's a lot the compiler does to translate this into equivalent dot-syntax. Besides the usual second and subsequent from clauses get turned into SelectMany calls we have let clauses that become Select calls with projections, both of which use transparent-identifiers. As I am about to show, having to name these identifiers in the dot-syntax takes away from the readability of that approach.

I have a trick for exposing what the compiler does in translating this code to dot syntax. If you uncomment the two commented lines above and run it again, you'll get the following output:

N = 1, O = 6, K = 4

solution expression tree System.Linq.Enumerable+d_b8.SelectMany(O => Range(1, 8), (O, N) => new <>f_AnonymousType02(O = O, N = N)).Where(<>h__TransparentIdentifier0 => (<>h__TransparentIdentifier0.O != <>h__TransparentIdentifier0.N)).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType12(<>h_TransparentIdentifier0 = <>h_TransparentIdentifier0, NO = ((10 * <>h_TransparentIdentifier0.N) + <>h_TransparentIdentifier0.O))).Select(<>h_TransparentIdentifier1 => new <>f_AnonymousType22(<>h__TransparentIdentifier1 = <>h__TransparentIdentifier1, product = (4 * <>h__TransparentIdentifier1.NO))).Where(<>h__TransparentIdentifier2 => (<>h__TransparentIdentifier2.product < 100)).Select(<>h__TransparentIdentifier2 => new <>f__AnonymousType32(<>h_TransparentIdentifier2 = <>h_TransparentIdentifier2, K = (<>h_TransparentIdentifier2.product % 10))).Where(<>h_TransparentIdentifier3 => (((<>h_TransparentIdentifier3.K != <>h_TransparentIdentifier3.<>h_TransparentIdentifier2.<>h_TransparentIdentifier1.<>h_TransparentIdentifier0.O) AndAlso (<>h_TransparentIdentifier3.K != <>h_TransparentIdentifier3.<>h_TransparentIdentifier2.<>h_TransparentIdentifier1.<>h_TransparentIdentifier0.N)) AndAlso ((<>h_TransparentIdentifier3.<>h_TransparentIdentifier2.product / 10) == <>h_TransparentIdentifier3.<>h_TransparentIdentifier2.<>h_TransparentIdentifier1.<>h_TransparentIdentifier0.O))).Select(<>h_TransparentIdentifier3 => new <>f_AnonymousType4`3(N = <>h_TransparentIdentifier3.<>h_TransparentIdentifier2.<>h_TransparentIdentifier1.<>h_TransparentIdentifier0.N, O = <>h_TransparentIdentifier3.<>h_TransparentIdentifier2.<>h_TransparentIdentifier1.<>h_TransparentIdentifier0.O, K = <>h__TransparentIdentifier3.K))

Putting each LINQ operator on a new line, translating the "unspeakable" identifiers to ones we can "speak", changing the anonymous types to their familiar form and changing the AndAlso expression-tree lingo to && exposes the transformations the compiler does to arrive at an equivalent in dot-syntax:

var solutions = 
    Enumerable.Range(1,8) // from O in Enumerable.Range(1,8)
        .SelectMany(O => Enumerable.Range(1, 8), (O, N) => new { O = O, N = N }) // from N in Enumerable.Range(1,8)
        .Where(temp0 => temp0.O != temp0.N) // where O != N
        .Select(temp0 => new { temp0 = temp0, NO = 10 * temp0.N + temp0.O }) // let NO = 10 * N + O
        .Select(temp1 => new { temp1 = temp1, product = 4 * temp1.NO }) // let product = 4 * NO
        .Where(temp2 => temp2.product < 100) // where product < 100
        .Select(temp2 => new { temp2 = temp2, K = temp2.product % 10 }) // let K = product % 10
        .Where(temp3 => temp3.K != temp3.temp2.temp1.temp0.O && temp3.K != temp3.temp2.temp1.temp0.N && temp3.temp2.product / 10 == temp3.temp2.temp1.temp0.O)
        // where K != O && K != N && product / 10 == O
        .Select(temp3 => new { N = temp3.temp2.temp1.temp0.N, O = temp3.temp2.temp1.temp0.O, K = temp3.K });
        // select new { N, O, K };

foreach(var i in solutions)

Which if you run you can verify that it again outputs:

N = 1, O = 6, K = 4

...but would you ever write code like this?

I'd wager the answer is NONBHN (Not Only No, But Hell No!) - because it's just too complex. Sure you can come up with some more meaningful identifier names than "temp0" .. "temp3", but the point is that they don't add anything to the code - they don't make the code perform better, they don't make the code read better, they only ugly-up the code, and if you were doing it by hand, no doubt you would mess it up a time or three before getting it right. Also, playing "the name game" is hard enough for meaningful identifiers, so I welcome the break from the name-game that the compiler provides me in query comprehensions.

This puzzle sample may not be real-world enough for you to take seriously; however, other scenarios do exist where query comprehensions shine:

  • The complexity of Join and GroupJoin: the scoping of range variables in query comprehension join clauses turn mistakes that might otherwise compile in dot-syntax into compile-time errors in comprehension syntax.
  • Any time the compiler would introduce a transparent-identifier in the comprehension transform, comprehensions become worthwhile. This includes the use of any of the following: multiple from clauses, join & join..into clauses and let clauses.

I know of more than one engineering shop in my hometown that has outlawed comprehension syntax. I think this is a pity as comprehension syntax is but a tool and a useful one at that. I think it's a lot like saying, "There are things you can do with a screwdriver that you can't do with a chisel. Because you can use a screwdriver as a chisel, chisels are banned henceforth under decree of the king."

share|improve this answer
-1: Wow. The OP was looking a little advice. You churned out a novel! Would you mind tightening this up a bit? –  Jim G. Sep 4 '12 at 3:54
add comment

SQL-like is a good way to start. But as it is limited (it supports just those constructions that your current language supports) eventually developers go to extension-methods style.

I would like to note that there are some cases which may be easily implemented by SQL-like style.

Also you can combine both ways in one query.

share|improve this answer
add comment

I tend to use the non-query syntax unless I need to define a variable mid-way though the query like

from x in list
let y = x.DoExpensiveCalulation()
where y > 42
select y

but I write the non-query syntax like

x.Where(c => filter)
 .Select(c => datatransform)
share|improve this answer
add comment

I always use the extension functions because of the ordering. Take your simple example- in the SQL, you wrote select first- even though actually, the where got executed first. When you write using the extension methods, then I feel much more in control. I get Intellisense about what's on offer, I write things in the order that they happen.

share|improve this answer
I think you'll find that in the "query comprehension" syntax the ordering on the page is the same as the order that the operations happen in. LINQ does not put the "select" first, unlike SQL. –  Eric Lippert Jun 16 '11 at 17:19
add comment

I like the extension function too.

Maybe cause it is less of a leap of syntax in my mind.

It feels more readable to the eye too, especially if you are using third party frameworks which have linq api.

share|improve this answer
add comment

Here's the heuristic that I follow:

Favor LINQ expressions over lambdas when you have joins.

I think that lambdas with joins look messy and are difficult to read.

share|improve this answer
add comment
