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.