JeremyBytes - Lambdas & LINQ in C# - Part 1: Lambda Expression Basics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this is Jeremy Clarke of Jeremy bytes calm and over the next few videos we'll be taking a look at lambda expressions and link in c-sharp today we'll be looking at the basics of lambdak spreche ins including the anatomy some of the syntax and also captured variables now we do find lambda expressions in a lot of different situations including link language integrated query and again we'll be spending quite a bit of time on this we also see them when we're dealing with the built-in delegate types func of T and action of T if you want some more information on delegates in general and func specifically you can check out my other video series c-sharp delegates another place we see lambda expressions is in callbacks and event handlers now the problem is the first time we walk up to these things we have a general idea of what's going on but it's not until we get to the specifics of what lambda expressions are that we start to really understand this now lambda expression is simply an anonymous function this lets us use lambda expressions as delegates in our code and we're going to see quite a bit of that as we go along now when we look at a lambda expression itself there's just three parts to it on the left hand side we have the parameters and this could be 0 one or more parameters then we have the equals greater than sign this is the goes to operator and it's also known as the lambda operator then on the right hand side we either have an expression or a series of statements here's an example of an expression lambda and we can see we have a parameter of type person that's also called person then we have the goes to operator and then we have an expression that will evaluate to either true or false in this case now a statement lambda does not return a value but it does perform some type of work so in this case our parameters are object sender and event args args then we have the goes to operator and then we have a series of statements that perform some type of work now one great thing about lambda expressions is they have a lot of syntactic sugar that we can add to them to make our expressions very very compact this also happens to be the thing that throws people off when they approach lambdas for the first time now the first thing we talked about is how we name parameters it's very common to use a single letter for parameter names and lambda expressions this is not required we can name our parameters whatever we like but because lambda expressions syntax is usually so compact we'll use single letter parameter names just to try to keep things short but now let's take a look at a few of the syntactic variations that may make lambdak spreche ins a little harder to read but they are very useful the first is called parameter type inference what this means is that if the compiler can figure out the types of the parameters we don't have to put them in so here we see our parameters s and E without any type specified now these are still strongly typed the difference is the compiler can figure it out so we don't have to type it in another variation is that parentheses are optional when we have a single parameter so in this case we just have one parameter e all by itself and because we just have the one parameter we don't need the parentheses around it this is very common to see especially when we're looking at linked methods now to make things even shorter if we only have a single statement the curly braces around it are optional so we can see that a combination of single character parameter names along with parameter type inference along with no parentheses around a single parameter along with no braces around a single statement creates a very very compact syntax now there is one other variation and that is if we have no parameters at all we just have a set of empty parentheses where the parameters normally go this isn't very common when we're talking about link but it can be common when we're talking about delegates with other frameworks so now that we've seen some of the syntactic variations let's jump over to the code to see this in action and also take a look at captured variables so here we are in visual studio and let's take a look at this project by running it to start things off so here we can see on the left hand side we do have a number of UI elements including selected item a space for some filters a way to order our data then down at the bottom we have a refresh button and then on the right hand side we have a list box now if we look at the code behind for our form right now we'll see it's not filled in right now all we have is a placeholder for our buttons click event handler so to start off with let's take a look at where we'll be getting our data now in our scenario another team is providing a library for us and what they've done is they've provided a class called people repository and this is providing data using something known as the event asynchronous pattern now when we use the event asynchronous pattern there's basically two parts to it we have an asynchronous method call to kick things off and in this case we have something called get people async now notice this returns void that's because as soon as we call this method it will return immediately and our application will continue processing now what we see next is that we have an event called get people completed this event will fire after our asynchronous process has completed so when our code will just hook up an event handler to get people completed and then when the data comes back from our library that event will fire and we'll be able to get the data out from the event args if we look at the get people completed event args we see it has a result property and this is an ienumerable of person and if we take a peek into our person class we'll see that this is a very simple class that just has four properties a first name a last name a start date and a rating now to use this library we'll start out by just hooking things up the way we normally would without lambda expressions at all so for this I'll just create an instance of our repository and we'll go ahead and call it repository and we'll new up people repository and then if we say repository dot get people notice that we have both get people async and get people completed so that's our asynchronous method call as well as the event we need to hook up to now when we use the event asynchronous pattern we actually want to hook up the event handler first that's because there's a very slight chance that our event will fire before we've had a chance to hook up the event handler so if we hook up the event handler first we won't have to worry about that now I'm going to let Visual Studio do all the work for me here so I'm just going to say plus equals and notice Visual Studio offers to create an event handler for us so we'll press tab and it gives us a chance to rename it but I'll go ahead and keep this and just hit tab again now inside our event handler we're going to want to use the result that's coming out of our event args and notice result is an ienumerable of person what that means is that we can directly assign this to our list box so we'll just say person list box item source equals e dot result now the last thing we need to do is kick off our asynchronous process so we'll say repository get people async and again that will fire off our asynchronous process when that process is complete the event will fire and our repository underscore get people completed method will run so now if we run our application and click the button we'll see exactly that so we do have data in our list box now is another feature if I select an item in the list box such as Dylan hunt we see that the selected item is populated in the upper right-hand part of our screen and we can see as the selection changes our selected item will change as well but notice what happens when I click the refresh button the selected item goes away and this makes perfect sense when we look at our code in our event handler what we're doing is we're replacing the contents of the list box every time we click the button so the list box doesn't know it's actually getting the same data back so it discards everything it has and reloads it with the data that we give it and part of that process is discarding the selected item now what we have here is known as a named delegate when we hook up our event handler we're hooking up a named delegate and that delegates name is repository underscore get people completed now I talked about how lambda expressions can be used to create anonymous delegates let's see if we can do that ourselves so what's an anonymous delegate well it's just a delegate without a name and to create an anonymous delegate what we'll do is inline the code for method so I'm going to highlight the prayer amateurs as well as the method body and I'll just keep ctrl C to copy and then up here where we're doing the assignment instead of assigning to our named delegate I'm just going to use the delegate keyword and then paste and so what I've just done is in-line this method now we can see visual studios not very happy with us now and that's because of the names of our parameters we already have something called sender in the same scope and the same is true for E so what we'll do is we'll just rename our parameters so we'll call this repo sender and then we'll call this repo args and then we'll need to rename this to repo args as well so now we can see the visual studio is happy with us so what we've just done is we've moved from a named delegate to an anonymous delegate in fact I'm going to comment out our named delegates so that we know it's not being used and if we run our application we'll see that we get exactly the same results we had before so when we click the refresh button we do get data and if we select an item and click the refresh button again that selected item does go away now we said that lambda expressions can be used as anonymous delegates well we have an anonymous delegate right here that means we can change this to a lambda expression all we have to do for this is delete the delegate keyword and then in between our parameters and method body we just need to add that goes to operator now we have a lambda expression and just to show that things still work we'll go ahead and run our application and we see we do still get data populated but now that we have a lambda expression we can start taking advantage of the syntactic variations the first one that we talked about was parameter type inference that means that if the compiler can figure out the types we don't have to put them in so notice I can actually remove sender and get people completed event args now these are still strongly typed if I hover over these we see that repo sender is still of type object and repo args is of type get people completed event args now the reason we're allowed to do this is the compiler can figure out the types of the parameters why well it's based on this get people completed event that we're hooking up to because this is an event handler the only methods that were allowed to hook up to this have to have two parameters one of type object and one of type get people completed event args and we can see this by trying to add a third parameter so if I try to add a third parameter we'll see that we have a very small red squiggly and when we build we will get a compiler error and we can see that our error message says delegate does not take three arguments and then of course if we try to use these parameters inside our code like repo args we'll see that it does have a result property which is what we expect from get people completed event args and in this case it has the four standard methods that all objects have now if I wanted to make this code shorter I could change these to single character parameter names I'll go ahead and leave the parameter names that we have here when we look at link later on we'll start using those single letter parameter names now another thing that I could do since we just have a single statement is I can get rid of the curly braces and this will still work exactly the same way that it did before so if we run our application we'll see we do get data and if I select Isaak Ambu we'll see we have our selected item and then if i refresh it our selected item is cleared so our behavior is exactly the same as we had when we had our name to delegate now in this particular case we are going to have some more code so I'll go ahead and put the curly braces back in so now that we have the basics of our lambda expression in place let's try to fix that selected item problem that we have so again the reason why our selected item gets cleared is because we completely replace the items in our list box so let's think about how we would fix this in code if I wanted to maintain the selected item what would I do well one thing that I could do is save off a copy of the selected item before i refresh the data and then after refreshing the data I can go back in and see if I can locate that item in the list box so let's go ahead and do just that so in our method I'll create a variable of type person called selected person and we'll assign this to person list box dot selected item and then I'll say as person now when we use as to do a cast if for some reason selected item is not a person this will just return null rather than throwing an exception and in our case null is perfectly fine because we may not have a selected item so now that we've saved off this selected person let's use it inside the body of our lammed expression so again I'm putting this in after we refresh the items in our list box so the first thing I'll do is I'll check to make sure selected person is not equal to null and if it's not null I'll go ahead and loop through all of the items in our list box so we'll say for each person in person list box items and then I'll check to see if the current person matches our saved item now unfortunately I don't have a primary key on this so we're going to have to do it based on the first-name and lastname properties so we'll say if person dot first-name equals selected person dot first-name and person dot last name equals selected person dot last name then we know that we have the item that we want and we can go ahead and take our person list box and set its selected item to the current item in our iteration so let's go ahead and just review this code one more time so again at the very top we're saving off a copy of our currently selected item and then inside the body of our lammed expression we set the items in our list box and then if the selected person is not null well go ahead and loop through all of the items in our list box and we'll try to find an item that matches based on the first name and the last name if we do find that item we'll go ahead and set that as the selected item in our list box so now let's go ahead and run our application to see what we have so if I click the refresh button we'll see that we do still get our items populated and if I click on Dylan hunt we see it as the selected item and if I click the refresh button we see that Dylan hunt is still the selected item so we are maintaining that selection when we refresh our data now the code we have looks pretty straightforward but it is a little bit deceptive because I just took advantage of a feature of lambda expressions called captured variables let me show you what I mean by that by putting a couple breakpoints in here so I'm going to put a breakpoint here as well as a breakpoint here now when we run our application the first time through I'll go ahead and just skip over these breakpoints since we don't have a selected item and then I'll select Dylan hunt and we'll click refresh again so let's go ahead and step through this code and for this I'm going to be using this button step over which is f10 so the first thing we do is we save off our selected person and if we look at this we see that it is populated and it does contain Dylan hunt then from here we new up our repository and then we hook up our event handler now notice this entire section is highlighted that's because we're simply doing the assignment we're not actually running the code in the body of our lammed expression at this point and then if we keep going we call get people async and then we hit the bottom of the method now this is where things get interesting because if we look at our selected person variable this is a method level variable what normally happens when we hit that bottom curly brace of our method that means that variable goes out of scope and it's eligible for garbage collection but that's obviously not what's happening in this case if I go ahead and run from here notice now our breakpoint just hid the body of our lambda expression that's because that long-running process has returned and that event handler has fired returning our data now if we step through this code and we get to the selected person variable we'll see that it is still populated and it is still populated with our value of Dylan hunt that means that we can start looping through trying to find that item and if we do find it will actually set the selected item so how does this actually work well again that's a cool feature of land expressions called captured variables this actually works with anonymous delegates as well inside the body of our lambda expression were allowed to use any objects and variables that are currently in scope when we do the assignment so since we're assigning our lambda expression inside this refresh button underscore click method we actually have access to all of the method level variables including selected person and if we wanted we could even use the parameters object sender and routed event args e inside of our lambda expression now other languages refer to this as a closure and what's happening is we're grabbing a reference to that variable not letting the garbage collector collect it so that we can use it in the body of our lambda expression even when that lambda expression runs later on after this method is completed now you might say what's the big deal with captured variables well the really cool thing about them is they let us scope our variables appropriately so let's think about how we would do the same functionality if we were still using our named delegate so remember our repository underscore get people completed method well that would mean our selected person variable would actually need to be a class level variable that way it would be available inside refresh button underscore clicks so we could do the assignment to that variable and then it would also be available in repository underscore get people completed so that we could use that to try to find the selected item but because we're using a lambda expression we can capture that variable and scope it more appropriately with a class level variable technically anything else in our class would be able to update that variable or read it but when we use a method level variable it's only accessible within this method itself and not to other members of the class now there is one important thing to understand about captured variables the value of the variable is the value at the time it's used not the value at the time that it's captured let me demonstrate this what we'll do is we'll change the value of our soul lected person variable so at the bottom of this method I'll just set it to null so now let's step through the code again and see what happens and again the first time through we'll just skip over it since we don't have a selection this time I'll select John Crichton and click refresh now as we go through this will see that our selected person is set and it does have a value of John Crichton and then when we do the assignment to our lambda expression this is where we're actually capturing the variable and at this point selected person is populated with the value of John Crichton but then we run get people async and then we set selected person to null so if we check the value now we'll see it is null now when we run and the body of our lambda expression runs we'll see that when we get to the part where it says is selected person null will see it is in fact null so we can see the value of the variable is the value at the time it's used not the value at the time its captured and if we keep running from here we'll see that we have no selected items set now in most cases we don't have to worry about this generally when we have a captured variable we're using it pretty locally and we're not changing the value of it there is one exception where you can run into trouble and that's if you capture the indexer of a for loop now I won't go into the details of that right now but we will be taking a look at that a little bit later on in the meantime if you check the links for this video you will find a link to an article that shows an example of trying to capture the indexer of a for loop and the really easy thing that we can do to get around the problem so today we've seen the basics of the lambda expression in this case we're using a statement lambda that we're hooking up to an event handler and again we have a very simple signature so we do have our parameters then we have our goes to operator and then we have the body of our lambda expression which again is a series of statements in this case and we did see how parameter type inference works because the compiler knows the types of our parameters we don't actually have to tie the min so instead of having object repo sender and get people completed event args repo args we can just have the names of our parameters and we also saw how captured variables work so in this case we had a method level variable selected person which was in scope when we created our lambda expression because of that we can grab a reference to that variable and we can use it in the body of our lambda even when it normally would be out of scope so that's it for the basics of lambda expressions we got to explore the syntax a little bit and we got to see captured variables one of the great features of lambda expressions in upcoming videos we're going to take a look at link language integrated query we're going to see some really cool features we're going to learn how to understand the syntax of the link methods and we're also going to see how lambda expressions play a key role in our link methods and as we'll go we'll see some differences between imperative programming and declarative programming sounds like a hard topic to understand but it's really not linked is one of my favorite features and I love using it in my code so until then be sure to visit w-w-w more more information and we'll see you next time
Info
Channel: Jeremy Clark
Views: 62,677
Rating: undefined out of 5
Keywords: C# (Programming Language), Lambda Expressions, Language Integrated Query (Programming Language), Anonymous Function
Id: MqxRpXUVZ8E
Channel Id: undefined
Length: 23min 30sec (1410 seconds)
Published: Mon Apr 06 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.