LINQ is awesome, right? It’s one of those things everyone loves from first sight. Like smartphones in the early days – you just know it’s right.
For
LINQ comes in two flavors – the Query Syntax and Method Syntax (aka Fluent Syntax). For example, the following is the same:
var numbers = Enumerable.Range(1, 100); //1,2,...,100
//query syntax:
var query = from n in numbers
where n % 3 == 0
select n * 2;
//method syntax:
var method = numbers
.Where(n => n % 3 == 0)
.Select(n => n * 2);
For some reason, most developers (including myself) feel much more comfortable with Method Syntax. I can’t explain it fully, but I think the reason is that programmers are used to regular method calls. Unlike query-syntax, which is sort of a new language (well, kind of like SQL but still much less familiar than C#).
There isn’t any distinct advantage of one over the other. In fact, any query syntax can be transformed into method syntax (See Dudi Keleti’s automatic Roslyn converter ).
However, method-syntax isn’t always a better syntax. There are several cases where query syntax is better, and this is what this post is all about. By better, I mean it makes more readable code. You’ll see some cool examples where method-syntax creates pretty complicated code that can be replaced by a short and neat query-syntax expression.
The awesome ‘let’ keyword
One of the nicest things about the query-syntax is the let keyword. It allows
var querySyntax =
from person in people
let yearsWorking = GetYearsWorking(person)
where yearsWorking > 4
orderby yearsWorking
select person.Name;
var methodSyntax = people
.Select(person => new {
YearsWorking = GetYearsWorking(person), Name = person.Name })
.Where(x => x.YearsWorking > 4)
.OrderBy(x => x.YearsWorking)
.Select(x => x.Name);
As you can see, with query syntax everything is nice and clean. Method-syntax isn’t terrible, but it requires you to create anonymous classes and use those for the rest of the query.
So whenever you want to “save” a value in addition to the queried collection, consider using the let clause.
Multiple data sources
If you have several data sources for the query, the query-syntax is probably a better choice. The reason is that you can use the from keyword several times. For example:
var rows = Enumerable.Range(1, 3); //1,2,3
var columns = new string[] { "A", "B", "C"};
var querySyntax = from row in rows
from col in columns
select $"cell [{row}, {col}]";
var methodSyntax =
rows.SelectMany(row => columns, (r, c) => $"cell [{r}, {c}]");
foreach (var cell in methodSyntax)
{
Console.WriteLine(cell);
}
//output:
//cell[1, A]
//cell[1, B]
//cell[1, C]
//cell[2, A]
//cell[2, B]
//cell[2, C]
//cell[3, A]
//cell[3, B]
//cell[3, C]
The purpose here is to get a collection with all the possible combinations from 2 sources. With query-syntax, the code is simple and self-explanatory. The method-syntax, on the other hand, requires a head-scratching to understand.
To understand how both ways work to give the same result, you can use the OzCode VS extension’s LINQ feature :
OrderBy with multiple orderings
In both query-syntax and method-syntax, you can easily perform multiple orderings. For example, we can order people by Age and then Income, where Age is the first ordering and Income the second one. This means that people with the same Age will be ordered by Income.
var people = new Person[]
{
new Person() {Age = 20, Income = 5000, Name = "Peter"},
new Person() {Age = 30, Income = 8000, Name = "Alfredo"},
new Person() {Age = 30, Income = 7000, Name = "Bo"},
new Person() {Age = 20, Income = 4000, Name = "Jo"},
new Person() {Age = 20, Income = 6000, Name = "Amanda"},
new Person() {Age = 30, Income = 5500, Name = "Maxim"},
};
var querySyntax = from person in people
orderby person.Age, person.Income
select $"{person.Age} {person.Income} {person.Name}";
var methodSyntax = people
.OrderBy(person => person.Age)
.ThenBy(person => person.Income)
.Select(person => $"{person.Age} {person.Income} {person.Name}");
//result
//20 4000 Jo
//20 5000 Peter
//20 6000 Amanda
//30 5500 Maxim
//30 7000 Bo
//30 8000 Alfredo
I admit, both syntaxes are good and the difference is not as big as in the other cases. But query-syntax is still nicer.
GroupBy vs group
The GroupBy extension method of method-syntax is pretty similar to group in query-syntax. For example:
var names = new string[] { "Alex", "George", "Alfredo", "Bo", "Greg", "Maxim" };
var querySyntax = from name in names
group name by name[0];
var methodSyntax = names
.GroupBy(name => name[0], name => name);
foreach (var pair in querySyntax)
{
var names1 = string.Join(", ", pair.ToList());
Console.WriteLine($"Key = {pair.Key} Names = {names1}");
}
//output:
//Key = A Names = Alex, Alfredo
//Key = G Names = George, Greg
//Key = B Names = Bo
//Key = M Names = Maxim
The method-syntax is a bit unclear. What does the second parameter stand for? Sure, once you think about it a bit, it becomes clearer. But I don’t want to think when I’m looking at code, I want to read it like a book. A children’s book if possible.
Joins are fun with query-syntax
Well, maybe joins are never truly fun, but they are much nicer with query-syntax. Here is inner join for example:
var categories = new Category[]
{
new Category() {Name = "Toys", ID = 1},
new Category() {Name = "Electrical", ID = 2},
};
var products = new Product[]
{
new Product(){Name = "Toy car", CategoryID =1 },
new Product(){Name = "Blender", CategoryID =2 },
new Product(){Name = "Washing machine", CategoryID =2 },
new Product(){Name = "Bear", CategoryID =1 },
};
var querySyntax =
from category in categories
join prod in products on category.ID equals prod.CategoryID
select new { ProductName = prod.Name, Category = category.Name };
var methodSyntax = categories.Join(products,
category => category.ID,
prod => prod.CategoryID,
(category, prod) => new {ProductName = prod.Name, Category = category.Name});
// result:
// ProductName: Toy car, Category: Toys
// ProductName: Bear, Category: Toys
// Blender - Electrical
// Washing machine - Electrical
In the method-syntax way, the 2nd and 3rd parameters of Join are compared. But unlike in query-syntax, it’s not really clear from the code. In query-syntax it’s much clearer with
join prod in products on category.ID equals prod.CategoryID
As a rule of thumb, whenever you need to Join collections, the query-syntax is going to be better. And by better I mean more readable and easier code.
Summary
In most cases, with simple operators like Where, Select and OrderBy the method-syntax is great. It provides an easy-to-understand functional syntax. You can switch to query-syntax for those, but I don’t recommend it. Even if you get used to it, remember that most programmers still find method-syntax more readable.
In some special cases, like the ones described above, query-syntax can be better. Those cases are:
- Multiple data sources
- “Saving” values for later in the query (‘let’ keyword)
- Order-By with multiple orders
- Group-By’s
- Joins
As I said in the beginning, there’s no distinct advantage of one syntax over the other besides readability. There’s even a cheat sheet if you want to convert between them.
> var methodSyntax = names
> .GroupBy(name => name[0], name => name);
Personally I prefer writing this way:
var methodSyntax = names
.GroupBy(name => name[0]);
The result is the same but more readable and closer to the query form.
Thanks SS, good example
Unfortunately, a cheat sheet is not accessible anymore =_(
Hey, nice article!
The link to the cheatsheet(http://www.bartdesmet.net/b...) Is not resolving for me. Do you have an alternative URL?
Thanks, it probably went down very recently. I didn't find any alternative, but I'll try to contact Bart and ask for permission to upload his cheat sheet.
Thanks.
Could add nice sample with many joins Inner and left to see the huge difference in syntaxes.
I actually tried to add such a sample but couldn't make it for some reason. Don't remember exactly but I think it was too complicated.
What about the difference in performance between both approaches?
Technically "Query Form" does not exist as a language and it is only a syntactic sugar. Compiler translates Query form into the same Method Call Chain form. That said there may be some cases where compiler might not translate Query form into a method syntax in an optimal form causing some unnecessary intermediate steps or choosing a more expensive solution to achieve the same result.
I do not have a specific example of that though because I've encountered that many years ago, but it is one of the reasons why I stick to method chain syntax. Another reason is because query form can only do maybe half the stuff method syntax can and it feels very ugly trying to mix them.
I have a more practical distinction, based on what kind of code you are writing. Not surprisingly, query syntax works a lot better for making queries to providers using SQL, the biggest advantage being join and let that you mentioned.
My question was the title of your article. My answer came from the content of said title. Nicely done. :)
Thanks Larry!
Thank you
Awesome advise, good concrete examples when query syntax really adds value (I'm in the camp of query syntax anyhow, but this makes it really concrete!).