Anonymous Methods, Lambdas and LINQ

… 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?”

1
dc.Categories.OrderBy(c => c.Name);

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Customer
{
public Customer(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName
}
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}

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.

1
2
3
4
5
6
7
8
9
10
11
public static void Main()
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer("Susan", "Ibach"));
customers.Add(new Customer("Christopher", "Harrison"));
customers.Add(new Customer("Dave", "Baxter"));
foreach(Customer customer in customers) {
Console.WriteLine(customer);
}
}

Again - pretty straight forward. And the output will of course be exactly what we’d expect:

1
2
3
Ibach, Susan
Harrison, Christopher
Baxter, Dave

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.

1
customers.Sort(); // Line 7

Result:

1
Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. ---> System.ArgumentException: At least one object must implement IComparable.

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.

IComparable is an interface with one method – CompareTo(object). 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 LastName.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Customer : IComparable
{
// existing code
public int CompareTo(object obj)
{
// put all NULL objects at the topic
if(obj == null) return 1;
Customer otherCustomer = obj as Customer;
if(otherCustomer != null) // obj is a customer
return this.LastName.CompareTo(otherCustomer.LastName);
else
throw new ArgumentException
("Object is not a Customer", "obj");
}
}

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 String.
Line 13 - if it turns out that obj is not a Customer, throw an ArgumentException.

If we run the code again, we now get the result that we were hoping for:

1
2
3
Baxter, Dave
Harrison, Christopher
Ibach, Susan

Cool.

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Customer:
IComparable, IComparable<Customer>
{
// existing code
public int CompareTo(object obj)
{
// put all NULL objects at the top
if(obj == null) return 1;
Customer otherCustomer = obj as Customer;
if(otherCustomer != null) // obj is a customer
return this.CompareTo(otherCustomer);
else
throw new ArgumentException("Object is not a Customer", "obj");
public int CompareTo(Customer other)
{
// put all NULL objects at the top
if(other == null) return 1;
return this.LastName.compareTo(other.LastName);
}
}
}

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 IComparable and IComparer is that IComparable is for sorting that specific class (which is why Customer implemented IComparable), while IComparer is for sorting other classes - a utility if you will. Let’s create a class that can sort Customer objects by FirstName.

1
2
3
4
5
6
7
8
9
10
11
12
public class CustomerSorter : IComparer<Customer>
{
public int Compare(Customer lhs, Customer rhs)
{
// put nulls at the top of the list
if(lhs == null) return -1;
if(rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
}
}

The main difference, besides calling CompareTo on 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.

1
2
3
// all other code identical
customers.Sort(new CustomerSorter());

When we run the code now, we get everything sorted by FirstName.

1
2
3
Harrison, Christopher
Baxter, Dave
Ibach, Susan

Cool.

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 Sort?

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 CustomerSorter.

1
2
3
4
5
6
7
8
9
10
// added to Program class
private static int SortByFirstName(Customer lhs, Customer rhs)
{
// put nulls at the top of the list
if(lhs == null) return -1;
if(rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
}

Want to know a secret? I simply copied and pasted from CustomerSorter class and changed public to private, instance to static, and the name to SortByFirstName.

Now we just need to tell the Sort method to use our new SortByFirstName method.

1
2
3
// identical code except for Sort call
customers.Sort(SortByFirstName);

And as before, the result is the same - sorted by FirstName.

Cool.

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 Sort?

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 Sort method.

1
2
3
4
5
6
7
// identical code except for the Sort method
customers.Sort(delegate(Customer lhs, Customer rhs) {
if (lhs == null) return -1;
if (rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
});

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 FirstName.

Cool.

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 Customer objects.

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.

1
2
3
4
5
6
7
// identical code except for call to Sort
customers.Sort((lhs, rhs) => {
if (lhs == null) return -1;
if (rhs == null) return 1;
return lhs.FirstName.CompareTo(rhs.FirstName);
});

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 lhs and 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 FirstName. Cool.

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.

With 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:

1
2
3
4
5
6
// updating the foreach loop
// all other code remains the same
foreach (Customer customer in
customers.OrderBy(c => c.FirstName)) {
Console.WriteLine(customer);
}

Couple of things to notice here.

First up is that unlike Sort, OrderBy is volatile, meaning that it’s going to return the sorted list rather than updating the list like Sort did.

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.

Cool.

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.