Anonymous Methods & Lamda Expressions in C#
With the advent of .NET 2.0 in November 2005 we were given something new called anonymous methods.
Anonymous methods are defined inline and are used when a delegate is normaly used. Because the method is defined inline it has no method name - hence the name anonymous methods.
Ok this is much easier to see in action so lets look at some code.
Lets first look at some coventional code. The following is a form with a button on it and shows how we use an event handler in the form of a written method to fire when the button is clicked. This is all pretty standard and normal.
In this code then under the hood the button class will have a delegate which is exposed as an event called Click. So when the button code raises the Click event it will simply execute all of the event handlers which have been added to the Click event. An event can have more than one subscriber. In the above example we have added the button1_Click event handler to the Click event.
With anonymous methods we can achieve exactly the same thing but with less code and more readability as follows:
Ok so this doesn't mean that we should write everything as anonymous methods. It just gives us a more concise way of achieveing the same thing and both methods have their ovbvious pros and cons. It's up to you to use what you think is right for your scenario. Typically though it will be in the kind of places where the code is very simple, doesn't change and doesn't need to be called directly.
Now you may have noticed that the anonymous method which we wrote didn't adhere to the delegate signature as defined in the Click event. The delegate should have a signature as follows:
So what's happening here? Well Microsoft designed the compiler so that we don't have to stick to the defined signature if we aren't going to use any of the parameters (eg sender or e). In this case then we just do what we did in the above example. If we did want to actually make use of the parameters though we would do so as follows:
So if we specify a signature then it must match what is expected otherwise we just don't specify one at all.
Ok so that's really all there is to anonymous methods.
In .NET 3.0 we had a new feature called Lamda expressions. In essense these are basically a more concise way of writing certain kinds of anonymous methods - particularly those which are functional in nature and use the input parameters. There goal is the same as anonymous methods, they just so in a more concise way.
Lamda expressions make use of an operator which looks like this and is called the lamda operator:
This is read out as "goes to" eg
x => x * 2 - reads x goes to x times 2
The code example we have been working with would look like this using lamda expressions.
Ok so this isn't a massive amount of conciseness (is that correct english?) compared with the previous version but when it is used for very simple functional bits of code it is very concise and readable. It is used particularly extensiveley within Linq.
The above example could also have been written as follows:
What we have done here is not specify the types of the parameters as the compiler can figure them out. This just aids readability and conciseness. There are however some instances when the compiler cannot infer the types in which case they can be input as in the first, longer example. It is normal practice though where possible to omit the parameter types. Also the brackets surrounding the parameters are optional if there is just 1 parameter.
Let us look at some sample code to see this kind of thing in action.
When we run this code we get the following results.
So what's happening here?
Well the Max method in Linq expects a delegate or lamda expression as an argument. When the method executes it is doing so against a collection of objects which implements the IEnumerable interface. Within the code it will use the delegate to figure out which property we want the max calculation to be performed against.
You will find that lamda expressions like this are used a lot in Linq so check out my article on Linq as follows: