Investigating Lambda expressions in LINQ
With the introduction of LINQ and its many flavours, developers started using this ORM technology to perform queries against an xml document, an sql server database, a in-memory collection of objects.
They were fascinated by its general purpose and its unified approach which can be summed up as "Learn one API-one model and use it against various data sources."
I say to people that are still new to LINQ or they do not know exactly why LINQ works the way it works, to have look at the enhancements applied to the C# language in version 3.0.
By that I mean, collection initialisers,object intialisers,extensions methods,auto-implemented properties,anonymous methods,anonymous types, the "var" keyword.Search the net for information on those.
Make sure before you go on implementing LINQ based applications, that you have all this knowledge under your belt.
In this post I will explore the issue that puzzles most developers, Lambda expressions.
I have seen people using LINQ with the query syntax which is more T-SQL like and more familiar to most developers.
Lambdas are used extensively in LINQ queries which are by nature pretty functional. So we must understand Lambdas if we want to use LINQ more efficiently.
Lambdas are a shorthand(shortcut) for anonymous methods/delegates. We all know that a delegate allow us to create a variable that points to a method.
Through that variable we can invoke the method at any time.So just to make sure that everyone follows along, Lambdas are essential in LINQ method syntax.
I will demonstrate that with a hands on example using an asp.net web site and c#.I will use a simple array of strings to do that.
1) Fire up Visual Studio 2008/2010. Express editions will work fine.
2) Create an empty web site. Give it the name of your choice.
3) Add a web form item to your site. Leave the default name
4) We will try something first with delegates and then we will move on to show the same example using Lambdas
5) Let's just say that we want to find all names from a list of names that contain the letter "A" and letter "B". We can solve that problem without using delegates but in this example I will use delegates.
6) Type this code inside the _Default class (the first line in the code below is just for reference)
public partial class _Default : System.Web.UI.Page
{
public delegate bool MyUsefulStringFunctions(string myS);
public static bool ContainsA(string s)
{
return s.Contains("A");
}
public static bool ContainsB(string s)
{
return s.Contains("B");
}
public static string[] ManipulateArray(string[] theStrings,
MyUsefulStringFunctions theFunction)
{
ArrayList theList = new ArrayList();
foreach (string s in theStrings)
{
if (theFunction(s))
{
theList.Add(s);
}
}
return (string[])theList.ToArray(typeof(string));
}
7) First I create a delegate that returns a type bool and defines an input parameter of type string.Remember, this is like defining an object type but what we actually see is a method signature for a function.
public delegate bool MyUsefulStringFunctions(string myS);
8) Then I create two instances of that delegate. Those two methods return bool and have an input parameter of type string.
public static bool ContainsA(string s)
{
return s.Contains("A");
}
public static bool ContainsB(string s)
{
return s.Contains("B");
}
9) Now we can pass these methods as an input parameter to another method I have created.
public static string[] ManipulateArray(string[] theStrings,
MyUsefulStringFunctions theFunction)
{
ArrayList theList = new ArrayList();
foreach (string s in theStrings)
{
if (theFunction(s))
{
theList.Add(s);
}
}
return (string[])theList.ToArray(typeof(string));
}
This method accepts an array of strings and accepts an instance of the delegate.Then for each string in the array of strings that I pass to this method I will get this delegate (algorithm) applied to them.
All those strings that satisfy the algorithm (e.g contain the letter A) will be added to a new array of strings and returned back from the method.
10) In the Page_Load event handling of the Default.aspx page routine type
string[] names = { "Aidan", "George", "Bryony", "Mary", "Joy", "Alastair",
"John", "Oliver", "Ken", "Jessy", "Joddie", "Helen", "Wesley", "Elvis" };
string[] mynamesA = ManipulateArray(names, ContainsA);
string[] mynamesB = ManipulateArray(names, ContainsB);
foreach (string s in mynamesA)
{
Response.Write(s);
Response.Write("<br/>");
}
11) I am defining an array of strings(names). Then I call the ManipulateArray method by passing the array of strings (names) and as a second parameter I pass ContainsA , which is an instance of our delegate declaration.
I save the return results of my method to another array(mynamesA,mynamesB) and I just loop through it.
Run your application and see the names starting with A printed out on the screen.Make sure you add breakpoints so you can see the flow of the execution.Obviously we can achieve that end result without using delegates. I just wanted to tell/remind you what delegates are and how we use them.
12) Now I am going to rewrite my small application by using anonymous methods
- comment out this block of code
//public static bool ContainsA(string s)
//{
// return s.Contains("A");
//}
//public static bool ContainsB(string s)
//{
// return s.Contains("B");
//}
- comment out everything inside the Page_Load event handling routine, and hen type
string[] names = { "Aidan", "George", "Bryony", "Mary", "Joy", "Alastair",
"John", "Oliver", "Ken", "Jessy", "Joddie", "Helen", "Wesley", "Elvis" };
string[] mynamesA = ManipulateArray(names, delegate(string theS)
{ return theS.Contains("A"); });
foreach (string s in mynamesA)
{
Response.Write(s);
Response.Write("<br/>");
}
Make sure your application runs as expected.We pass to the method (ManipulateArray) an array of strings like before and yes you guessed it, a delegate as a second input parameter. A delegate that if you look carefully is of type
public delegate bool MyUsefulStringFunctions(string myS);
because it returns a boolean and accepts a string.Well, you must be thinking when I am going to learn about lambdas... First of all I am going to write more posts on LINQ quantifiers,operators using both the query syntax and the method syntax. In this example I am going to change our small application to include lambdas. But as I said again the lambdas are like a shorthand definition of anonymous methods. They are anonymous methods in disguise.
I want you to just change this line of code
string[] mynamesA = ManipulateArray(names, delegate(string theS)
{ return theS.Contains("A"); });
with this line of code.
string[] mynamesA = ManipulateArray(names, (theS =>theS.Contains("A")));
Run again your application.It will work.
theS is the input parameter. The => is the seperator and the theS.Contains("A") is just the algorithm applied to all of the strings in the names array.
We basically say "Evaluate every string we give you, and if it contains the letter A,return true otherwise return false."
Email me if you need the source code. Stay tuned for more posts with lambda expressions.
Hope it helps!!!!!