… oh my!
Lately, one of the most common questions I’ve received from my students is, basically, “What in the world is this syntax, and what does it mean?”
Well - it’s a lambda statement. But of course if you haven’t seen one, you need a bit more information than that.
Quite frequently, a full explanation would simply take too long, or send the class down another path far away from the topic at hand. What I want to do with this post is answer that question fully.
I’m going to answer the question by using one of my biggest philosophies when it comes to training, which is to explain it in the way that I understood it, in whatever method it was that made it finally click for me. In this case, that means stepping all the way back to the beginnings and showing essentially the progression that got us to where we are today.
That’s going to take a little while, so bear with me.
Trust me, we’ll get there.
Let’s take a simple class called
Customer that’s defined below:
Pretty straight forward. Couple of properties, a simple constructor. Looks good. Now let’s create a couple, put them into a list, and display them.
Again - pretty straight forward. And the output will of course be exactly what we’d expect:
Now let’s see if we can sort those customers. Fortunately,
List has a a
Sort method. Let’s update line 7 to call sort (code below) and run it to see what happens.
Well that wasn’t ideal… In a nutshell, what the runtime is trying to tell us is that we told it to sort a list of customers, but it has no idea how to sort our customers. Makes sense. How do we tell it to sort our customers? Well – by implementing
IComparable is an interface with one method –
CompareTo returns an integer based on the following criteria:
Current object (
this) is less than the other object, return a negative number
Current object (
this) is equal to the other object, return 0
Current object (
this) is greater than the other object, return a positive number
One thing that you’ll notice is that every primitive type (and strings) in .NET already implement
IComparable. This means we can take advantage of their implementation. Let’s update our
Customer class to implement
IComparable and sort by
The breakdown looks a bit like this:
Line 8 - see if the object is null. If it is, move it to the top of the list.
Line 10 - convert the object to a customer
Line 11 - if it turns out that obj is a
Customer, use the
CompareTo method on
Line 13 - if it turns out that obj is not a
Customer, throw an
If we run the code again, we now get the result that we were hoping for:
But…. If you look at the
CompareTo implementation, we’re having to cast the obj parameter to
Customer. Why can’t we just tell the
IComparable interface that we want people to pass in a
Customer and be done with it?
Fortunately – we can. The way that we do this is by using generics. In a nutshell, generics allow you to pass a type as you would a variable. So at design time we tell
IComparable prepare itself for
Customer objects. Let’s update our
Customer class again.
Cool - we have a Customer class that can be sorted.
But… It can only be sorted one way - by
LastName. If we wanted to sort by
FirstName, well - that’d require updating our class. Having to update our class every time we need a different sort order would be a pain.
Fortunately – we don’t have to. The .NET framework also includes an
IComparer interface. The difference between
IComparer is that
IComparable is for sorting that specific class (which is why
IComparer is for sorting other classes - a utility if you will. Let’s create a class that can sort
Customer objects by
The main difference, besides calling
FirstName, is that we have two parameters of type
Customer and we’re comparing one to the other. But the logic is still basically the same.
To use the new sorter, we simply pass a new instance of the object into the
Sort method on List.
When we run the code now, we get everything sorted by
But… If we have to create a new class every single time we need to change the sort order, well – that’s going to stink. There’s gotta be a better way.
Fortunately, there is. The .NET Framework gives us the ability to use delegates, which allow us to pass methods like we would objects.
Let’s take a look at our new
Compare() method that we created on our
CustomerSorter class. You’ll notice that it takes two parameters, each of type
Customer, and returns an integer. That’s it. And when we call
Sort and pass in the
CustomerSorter, it simply calls that method. Why can’t we just pass a method into
This is where that delegate, an object that points to a method, comes into play. Since it can be used like an object and passed in as a parameter, we can just tell
Sort to call that method directly. This is really the same thing we were doing before by passing in an instance of
CustomerSorter to the
Sort method, only this time we’re just passing in a method.
Our method just needs to match the same signature – two
Customer parameters and return an integer.
Let’s add a method to our
Program class that will use the same logic as our
Want to know a secret? I simply copied and pasted from
CustomerSorter class and changed
private, instance to static, and the name to
Now we just need to tell the
Sort method to use our new
And as before, the result is the same - sorted by
But… If we need to sort in several different orders, we don’t want to have to create a method each and every time. Wouldn’t it be nice if we could just inject the logic right into the call to
Fortunately, we can. We do this by creating an anonymous method. An anonymous method is a method that has no name. We just create the method signature by using a delegate, and pass it right into the
Just as before, we have the same logic (yes, I copied and pasted). We’re just declaring the method just as we normally would with only a couple of differences. First, we’re using the keyword delegate instead of using a method name. Second, we’re not specifying a return type. The reason is that
Sort already knows what the return type is – an integer – so the compiler doesn’t require it.
And, as before, the result is the same – sorted by
But… Why do we have to specify the types of the parameters? After all, we already told the list right up front that we were using
Fortunately, we don’t. This is where lambda expressions come into play. A lambda expression is just like an anonymous method, only with a couple more assumptions. In our case, since we know, and the compiler knows, that we are only dealing with
Customer objects, and we need to return an integer, we’re just going to declare our variables and move on.
The main difference between this and our anonymous method is the syntax and the fact that we’re not declaring data types. Since everyone, including the compiler, knows that
rhs can only be
Customer objects we don’t have to declare it. The => is just the syntax to indicate the start of the method, or lambda expression.
And, as before, the result is the same – sorted by
But… What about the normal situation where all we want to do is just say, “Hey .NET - sort this by ___ for me.”? Do we really have to create a method, even in a lambda expression, every single time?
Fortunately, we don’t. This is where Language Integrated Query (LINQ) comes into play.
In each of our method implementations, our code has simply taken advantage of the logic in the
String class. LINQ will do the same thing for us. We simply tell LINQ, “Hey – sort by this”, and it’ll handle the translations for us.
The first step to using LINQ is to leave behind the
Sort method that we’ve come to know and love. Unfortunately,
Sort doesn’t support LINQ.
When Microsoft introduced LINQ, they also introduced something called extension methods. Extension methods are a way of adding a method to an existing class without having to inherit from that class. The method that was added to the
List class, or more specifically
IEnumerable, for LINQ was
OrderBy we can, by using a lambda statement, simply tell LINQ the property we want to sort by. So the new code looks like this:
Couple of things to notice here.
First up is that unlike
OrderBy is volatile, meaning that it’s going to return the sorted list rather than updating the list like
Second is the fact that we’re not returning an integer. Again, LINQ will handle the translation for us. As long as we specify a property that implements
IComparable it will use that for the sorting.
Third is that LINQ uses deferred execution. In other words, it won’t actually do the sort until we use the results. In this case, we’re doing this when we use the foreach loop.
And now when we run the code we of course get the same results.
And that’s what that lambda statement is all about. It’s really just letting someone else create the query for us based on a couple of assumptions about our code and the types that we’re using.
From here, things actually get cooler. We of course have LINQ syntax, which allows us to write something similar to a SQL query. And, LINQ can also translate the queries for other environments, like SQL.
But for now, we’ll leave it here, with a very propeller head view of lambda statements. Hopefully this helped bring together what’s happening behind the scenes, and why we’re able to take the shortcuts we can take.