LINQ — Lambda Expression vs Query Expression

As you’re prob­a­bly aware of already, LINQ comes in two flavours – using Lamb­da expres­sions and using SQL-like query expres­sions:

Func<int, bool> isEven = i => i % 2 == 0;
int[] ints = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// using Query expression
var evensQuery = from i in ints where isEven(i) select i;
// using Lambda expression
var evensLambda = ints.Where(isEven);

Both yields the same result because query expres­sions are trans­lat­ed into their lamb­da expres­sions before they’re com­piled. So per­for­mance-wise, there’s no dif­fer­ence what­so­ev­er between the two.

Which one you should use is most­ly per­son­al pref­er­ence, many peo­ple pre­fer lamb­da expres­sions because they’re short­er and more con­cise, but per­son­al­ly I pre­fer the query syn­tax hav­ing worked exten­sive­ly with SQL. With that said, it’s impor­tant to bear in mind that there are sit­u­a­tions where one will be bet­ter suit­ed than the oth­er.

Joins

Here’s an exam­ple of how you can join sequence togeth­er using Lamb­da and query expres­sions:

class Person
{
    public string Name { get; set; }
}
class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

void Main()
{
    var magnus = new Person { Name = "Hedlund, Magnus" };
    var terry = new Person { Name = "Adams, Terry" };
    var charlotte = new Person { Name = "Weiss, Charlotte" };
    var barley = new Pet { Name = "Barley", Owner = terry };
    var boots = new Pet { Name = "Boots", Owner = terry };
    var whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    var daisy = new Pet { Name = "Daisy", Owner = magnus };
    var people = new List<Person> { magnus, terry, charlotte };
    var pets = new List<Pet> { barley, boots, whiskers, daisy };

    // using lambda expression
    var lambda = people.Join(pets,              // outer sequence
                             person => person,  // inner sequence key
                             pet => pet.Owner,  // outer sequence key
                             (person, pet) =>
                                 new { OwnerName = person.Name, Pet = pet.Name });

    // using query expression
    var query = from person in people
                join pet in pets on person equals pet.Owner
                select new { OwnerName = person.Name, Pet = pet.Name };
}

Again, both yields the same result and there is no per­for­mance penal­ties asso­ci­at­ed with either, but it’s easy to see why query syn­tax is far more read­able and expres­sive of your intent here than the lamb­da expres­sion!

Lambda-Only Functions

There are a num­ber of meth­ods that are only avail­able with the Lamb­da expres­sion, Sin­gle(), Take(), Skip(), First() just to name a few. Although you can mix and match the two by call­ing the Lamb­da-only meth­ods at the end of the query:

// mix and match query and Lambda syntax
var query = (from person in people
             join pet in pets on person equals pet.Owner
             select new { OwnerName = person.Name, Pet = pet.Name }).Skip(1).Take(2);

As this reduces the read­abil­i­ty of your code, it’s gen­er­al­ly bet­ter to first assign the result of a query expres­sion to a vari­able and then use Lamb­da expres­sion using that vari­able:

var query = from person in people
            join pet in pets on person equals pet.Owner
            select new { OwnerName = person.Name, Pet = pet.Name };

var result = query.Skip(1).Take(2);

Both ver­sions returns the same result because of delayed exe­cu­tion (the query is not exe­cut­ed against the under­ly­ing list until you try to iter­ate through the result vari­able). Also, because query expres­sions are trans­lat­ed to Lamb­da expres­sions first before being com­piled there will not be per­for­mance penal­ties either. BUT, if you don’t want delayed exe­cu­tion, or need to use one of the aggre­gate func­tions such as Aver­age() or Sum(), for exam­ple, you should be aware of the pos­si­bil­i­ty of the under­ly­ing sequence being mod­i­fied between the assign­ments to query and result. In this case,I’d argue it’s best to use Lamb­da expres­sions to start with or add the Lamb­da-only meth­ods to the query expres­sion.