Tutor HuntResources Computer Programming Resources
Lambda Expressions In C#
Lambda expressions in C#
Date : 06/10/2012
Author Information
Uploaded by : David
Uploaded on : 06/10/2012
Subject : Computer Programming
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" }; DisplayCounties(counties); Console.Read(); } static void DisplayCounties (string[] counties) { foreach (string c in counties) { Console.WriteLine(c); } } } }
And so if you run this code it will of course output all of the counties to the console. Now lets say we want to output counties to the screen but only for those which are shires - ie they end in shire. We could do this by writing a method which does just that and then our code would look like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" }; DisplayShireCounties(counties); Console.Read(); } static void DisplayCounties (string[] counties) { foreach (string c in counties) { Console.WriteLine(c); } } static void DisplayShireCounties(string[] counties) { foreach (string c in counties) { if (c.ToUpper().EndsWith("SHIRE")) { Console.WriteLine(c); } } } } }
Now supposed we wanted to extend this idea and display counties according to some other criteria too. Lets say we want counties which are not shires and counties with less than 7 characters. We could code more methods like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" };
DisplayShireCounties(counties); Console.WriteLine(" -"); DisplayNonShireCounties(counties); Console.WriteLine(" -"); DisplayCountiesWithLessThanSevenCharacters(counties); Console.Read(); } static void DisplayCounties (string[] counties) { foreach (string c in counties) { Console.WriteLine(c); } } static void DisplayShireCounties(string[] counties) { foreach (string c in counties) { if (c.ToUpper().EndsWith("SHIRE")) { Console.WriteLine(c); } } } static void DisplayNonShireCounties(string[] counties) { foreach (string c in counties) { if (!c.ToUpper().EndsWith("SHIRE")) { Console.WriteLine(c); } } } static void DisplayCountiesWithLessThanSevenCharacters(string[] counties) { foreach (string c in counties) { if (c.Length < 7) { Console.WriteLine(c); } } } } }
And so if we wanted another dozen methods to do different selections or filters then we could just carry on writing more methods. There is a better and more flexible way of doing this though and that is to use delegates. If you are not sure what delegates are then you need to get your head round that first before continuing with this article and you can do so here: http://www.audacs.co.uk/ViewPage.aspx?PageID=474 The code below shows this rewritten to use delegates. Note that this is better not just because you probably end up writing smaller and less verbose code but also because it is more felxible and easy to extend. So the new code looks like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { delegate bool PerformActionOnString (string s);
class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" }; DisplayCounties(counties, new PerformActionOnString(IsShireCounty)); DisplayCounties(counties, new PerformActionOnString(IsNotShireCounty)); DisplayCounties(counties, new PerformActionOnString(LessThanSevenCharacters)); Console.Read(); } static void DisplayCounties (string[] counties, PerformActionOnString method) { foreach (string c in counties) { if (method(c)) { Console.WriteLine(c); } } } static bool IsShireCounty(string county) { return county.ToUpper().EndsWith("SHIRE"); } static bool IsNotShireCounty(string county) { return !county.ToUpper().EndsWith("SHIRE"); } static bool LessThanSevenCharacters(string county) { return county.Length < 7; } } }
So we have got rid of all the different methods which outputted counties to the screen and replaced these with just one method called DisplayCounties. This method takes a string array as a parameter and also now takes a delegate instance as well. The delegate instance is of the type of PerformActionOnString which is a delegate signature we have declared at the top of the code. Any instance of the delegate must accept a single string as an argument and return a bool. Within our DisplayCounties method we then invoke the method this delegate refers to on each string in the array and if the boolean result is true we output the county to the console. This enables us to now write simple, smaller methods which do a comparison on one string and we then pass that into our DisplayCounties method via a delegate. So the client part of our code now looks like this:
DisplayCounties(counties, new PerformActionOnString(IsShireCounty)); DisplayCounties(counties, new PerformActionOnString(IsNotShireCounty)); DisplayCounties(counties, new PerformActionOnString(LessThanSevenCharacters));
And so now if we wanted a new method - lets say counties with an X in we would write our new comparison method like this:
static bool ContainsX(string county) { return county.ToUpper().Contains("X"); }
And then our client code would just have one extra line as follows:
DisplayCounties(counties, new PerformActionOnString(ContainsX));
Now if we wanted to simplify and compact our code even further we could do away with all of our comparison methods and use inline anonymous methods instead. If you are not sure what an anonymous method is, it is when we put the code for a method inline rather than putting a method name. So our new code would end up looking like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { delegate bool PerformActionOnString (string s);
class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" }; DisplayCounties(counties, delegate(string county) { return county.ToUpper().EndsWith("SHIRE"); }); DisplayCounties(counties, delegate(string county) { return !county.ToUpper().EndsWith("SHIRE"); }); DisplayCounties(counties, delegate(string county) { return county.Length < 7; }); DisplayCounties(counties, delegate(string county) { return county.ToUpper().Contains("X"); }); Console.Read(); } static void DisplayCounties (string[] counties, PerformActionOnString method) { foreach (string c in counties) { if (method(c)) { Console.WriteLine(c); } } Console.WriteLine(" -"); } } }
So in the highlighted yellow section we have put the entire method body but put the word delegate rather than a method name. So this method is inline and is anonymous as it doesn`t have a name. This leads to very compact code and is often a better way to go when this is the only part of your program you will use that method. The end result is exactly the same as the previous code but now the method is inline and anonymous. This now makes our code very easy to extend and you can do so with just one line of code! Ok so now we get to the point of the article - Lamda expressions. The above way of using inline anonymous methods is very wideley used and so to make our lives easier, Microsoft gave C# the ability to use lamda expressions. A lamda expression is a shorthand or easier way of defining anonymous methods. Lets take a look at out last piece of code but written with lamda expressions instead.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace LambdaExpressions { delegate bool PerformActionOnString (string s);
class Program { static void Main(string[] args) { string[] counties = new string[] { "Derbyshire", "Staffordshire", "Sussex", "Kent", "Yorkshire", "Nottinghamshire", "Avon", "Cheshire", "Rutland" }; DisplayCounties(counties, c => c.ToUpper().EndsWith("SHIRE")); DisplayCounties(counties, c => !c.ToUpper().EndsWith("SHIRE")); DisplayCounties(counties, c => c.Length < 7); DisplayCounties(counties, c => c.ToUpper().Contains("X")); Console.Read(); } static void DisplayCounties (string[] counties, PerformActionOnString method) { foreach (string c in counties) { if (method(c)) { Console.WriteLine(c); } } Console.WriteLine(" -"); } } }
So our old code looked like this: DisplayCounties(counties, delegate(string county) { return county.ToUpper().EndsWith("SHIRE"); });
And now this looks like this: DisplayCounties(counties, c => c.ToUpper().EndsWith("SHIRE"));
So when the lamda expression is compiled, the compiler will produce the same thing as the old delegate code - the lamda expression is just a shorter, easier to use facade for us humans who like things to be compact and simple. You can think of the c replacing delegate(string county) - The compiler can do this as it knows it is a lamda expression because of the => operator and it knows that the delegate arguments is just 1 string as it knows what kind of delegate the DisplayCounties method expects. The code to the right of the => operator is the main code which would be the delegate method. This should evaluate to the type the delegate should return. So the compiler knows that DisplayCounties expects a delegate as it`s second argument and that delegate is of type PerformActionOnString which returns a bool. Therefore the piece of code on the right of our => must evaluate to a bool. So when to use a lamda expression? Well anytime you have an anonymous method inline then you can use a lamda expression. If you wanted to, in our above code you could even do this kind of thing: PerformActionOnString m = c => c.ToUpper().EndsWith("SHIRE"); DisplayCounties(counties, m);
This resource was uploaded by: David