JeremyBytes - Lambdas & LINQ in C# - Part 2: Demystifying LINQ Methods

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this is Jeremy Clarke of Jeremy bytes calm and today we're going to continue our conversation about lambda expressions and Link last time we took a look at what lambda expressions are and the different syntactic variations that we have with those today we'll be looking at the link methods specifically we'll be demystifying the signatures that we see when we look at the documentation for link methods now link language integrated query is really awesome and there's a couple different ways that we can use this technology when we build link statements using query syntax it looks a lot like a query we would use against a sequel database this syntax is very approachable but unfortunately the number of keywords are limited the other way that we can use link is using what's known as the fluent syntax this is where we use the link extension methods directly in our code now personally I prefer the fluent syntax and one reason for that is we get access to all of the extension methods that we have available to us in link now one of the problems that we have when we use the fluent syntax is figuring out how to use the methods if we look in the documentation we see something that looks like this and our first reaction is to just back away from this slowly it has a lot of pieces but once we understand what those pieces are it's not very hard to interact with this method now a few common things that we'll see is that we're dealing with ienumerable in most of our situations now ienumerable is just an interface that describes an iteration something that we can step through one item at a time now it turns out pretty much every built-in collection in net implements the ienumerable interface which means we can use these methods on almost every collection that we come across now something else that will see in link methods our generic type parameters we will see these everywhere but once we figure out how these generic type parameters are related it's not very difficult to figure out how to use them in this code another cool thing about these link methods is they are extension methods and we can tell this by looking at the this keyword that we have on the first parameter now extension methods allow us to add methods as if we were extending the itself but in reality we're just doing a little bit of compiler trickery here if you want some more information on extension methods I do have another video in my channel that explains them now the other thing that we run into is funk funk is a built-in delegate type in dotnet and again the first time we see these they look a little cryptic but once we figure out what this really means they're pretty easy to work with if you want some more details on how to work with funk of T and action of T you can check out my other series on c-sharp delegates specifically episode 2 is all about getting funky and understanding how this built-in delegate works now when we're working with link I always treat funk as a big flashing sign that says put your lambda expression here when we have a funk it's telling us to stick a delegate in here and as we learn last time we can use lambda expressions as anonymous delegates and so that's what we'll be doing in our code so now let's jump back to our code and look at these things one at a time to get a good handle on how they work so here we are in visual studio and our code is exactly the way that we left it last time so let's run our application to see what we have so right now if I click the refresh button we do get data out of our library and if I click on an item we do see that the selected item shows up in the top right corner of our screen now we do have some other elements here as well specifically we have a section for filtering and we have a section for sorting so what we're going to do is we're going to use link to implement both of these and for this we're going to start out with filtering and for that we're going to want to look at our link methods so what I'm going to do is I'm going to open up help and take a look at ienumerable of T so if we select ienumerable of T what we'll see is the interface itself only has one method called get enumerator and this is how the iterations work when we use ienumerable but what's more important to us are the extension methods these give us a lot of options for interacting with our data and we can see we have things like aggregations averages selecting particular items copying getting counts the list just goes on and on now I would recommend at some point that you take a look through all of these extension methods that we have an ienumerable because what you'll find is there's a lot of very useful things that you didn't know about now the one that we want right now is way down at the bottom and it's this ware method that we have right here so let's click into this and look at the method signature now this is the same signature that we saw on the slide so we see that we have ware of T source now in our case we're dealing with a collection of person objects so everywhere that we see T stores in this method signature we can replace that in our minds with person since that's what we're dealing with so if we look at the return type this will return an ienumerable of person and if we look at our parameters we'll see that our first parameter is an ienumerable of person as well so we're going to take an ienumerable of person into our method and pass out an ienumerable of person now in this case the value that we're passing out will be a filtered collection and the filtering is based on this predicate parameter that we have here notice we have a func of T source bool so again this would be a func of person bool in our case now what exactly does this mean let's go ahead and click into func of T source bool and we'll look at this signature now as I mentioned earlier func is a built-in delegate type but it has generic type parameters to specify the different types so if we look at this method signature we see we have a func of T T result now if we look at this we can see that T is used as the parameter of this particular delegate and T result is the return type that's coming back from this so when we see a delegate that says func of TT result we know that the first item T is our parameter coming in and T result is the type that's coming back out that we need to return so if we go back to our where declaration again what we have is func of T source pool which is a func of person bool in our case and so what that tells us is that we need to create a delegate that takes a person as a parameter and returns a boolean a true/false value and logically this makes perfect sense we're setting up a filter so we need to tell which items we want included in our filter and for that we'll just pass back a true value now one other thing that I kind of skipped over was this that's used with the first parameter now since this is a public static method that's in a public static class and has this right before the first parameter that means this is an extension method so rather than creating a method that has two parameters source and predicate in this case we can actually treat this method as if it were a method on the source parameter object that we have so in that case we would say source dot where and then it would have one parameter which is a predicate and again if you do want some more information on extension methods I do have another video that's about 12 minutes long that'll show you all about them now one thing that's important here is we take an ienumerable and we return an ienumerable that means we can treat this method like a pass-through method so let's go ahead and start using this in our code and we'll put all of these pieces together now what I'm going to do here is I'm going to create a new method that will apply the filters and again since this takes an ienumerable and returns an ienumerable we can create a method that does that as well so we'll create a private method that returns an ienumerable of person and we'll call this add filters and this will take an ienumerable of person as a parameter and we'll go ahead and call this people now we do have to return something if no filters are applied so I'll just create a default case where we return the people object and that makes our method happy in this case so let's start off by looking at the name filter now for this we're going to be comparing the first name of our person object to a value that's in a textbox so the first thing I'm going to do is I'm going to see if our name filter checkbox is checked and if it is checked then we're going to go ahead and apply our filter now I mentioned that where is an extension method on ienumerable of T that means we can as if it's a method on any of our ienumerable objects so in this case I can say people dot and notice I have a big list of items here and that does include the wear method so we can see that this does act as if it were a method on our people object now there is a requirement here we do have to include the system dot link namespace this is where those extension methods live so if we go back down to our people object what we'll see is if we say people dot we have a much shorter list in fact the only item that we have is get a numerator which if you remember from our documentation is the one method that we have on the ienumerable interface but if we add system dot link now we have all of those other methods available to us as well now the good news is that system dot link is included by default in most file types when we're using c-sharp now let's look at the help that Visual Studio is giving us here now the interesting thing is that Visual Studio notice that we're using where as an extension method so if we look at the parameters we'll see it only has one parameter func of person bool now where did that first parameter go well that ienumerable of person comes right before our where method so for the parameter we have to fill in this func of person bool now again this is a delegate that's describing a method that takes a person as a parameter and returns a boolean value now last time we learned a pretty easy way of doing this with lambda expressions let's start out with a verbose lambda expression just so that we can see all of the elements clearly so we'll start out with a parameter of type person called person and then we'll use the goes to operator and then we'll return a true/false value so in this case we'll say person dot first-name compare equal to name textbox text so we're going to be checking the value in our text box against the first name property of our person object if it matches this will return true and we want that included in our collection now there is one other thing that we need to do this method if we look at where we see that it returns an ienumerable of person well we're not doing anything with that value right now so what I'm going to do is I'm going to set people equal to the return value of people dot where now this may seem a little strange because we're setting our value equal to the output that's coming from our method but one really nice thing about link is that they're lazy evaluated that means that this code doesn't run until we actually start iterating through the object so when I do this assignment here I'm not actually writing any code I'm just saying if someone starts to pull data out of this object I want you to make sure that you apply this filter while you're doing it so now that we have this we can actually use it where we're doing the assignment to our list box now if we remember our result that's coming back from our repository library is an ienumerable of person our add filters method takes an ienumerable of person and returns an ienumerable of person that means we can treat it like a pass through so now what will happen is we'll get the result out of our event handler and then we'll pass that to the add filters method that will apply any filters and then assign that to our list box so now let's run our application to see this in action if we click on the refresh button we get the data that we saw before and in this case I'm going to go ahead and select John Crichton as a selected item now I'm going to check the named filter checkbox which we see a set to John and click refresh again now we see we have filtered data and notice that our selected item is still staying selected that's because of the way that we implemented this earlier now if I select Dave Lister and then filter based on John we'll see that our selected item does go away because Dave Lister is not actually in our list box anymore but if we do select an item and it remains there between the filtering we see that it does stay selected now what we have right now is an extremely verbose lambda expression we can see this is taking up almost the entire line and this is one of the reasons why we have all of those syntactic variations on lambda expressions so we can make them extremely compact so let's start using some of the things that we learned last time now the first thing we talked about with single character parameter names and again this isn't a requirement but it is a convention now when I pick a single character for my parameter names I usually try to stick with whatever type I'm working with that helps my brain a little bit when I'm using this variable so when I'm dealing with a person object I'm likely to use P as the single character now we also learned about parameter type inference so if the compiler can figure out the type of our parameter we don't have to put it in and as we've already seen the compiler is telling us that we need a func of person bool here so it already knows that we need a delegate that has one parameter of type person so the compiler already knows we don't have to put it in now another syntactic variation is that if we only have one parameter we don't need to have parentheses around it and if we only have a single expression we don't need the curly braces and in fact we don't need the return keyword either so I can take out both of those and now we can see that we have an extremely compact lambda expression now this does exactly the same thing that our verbose version did if we run our application we'll see that we get the same results so if we do filter based on John our filter is applied but we can see that our syntax is much much more compact and again our P is strongly typed so it is of type person and we return a true/false value and that satisfies the signature for a delegate now I did have another filter there based on date ranges so let's go ahead and do that now the first thing I'm going to do is I'm going to do a little bit of parsing based on what's coming in from our text boxes so I'll create a couple of variables and I won't make you watch me do this and so we can see here I've created two variables one for the start year based on what's in our start date textbox and one for the end year which is what's in our end date textbox now obviously in a real application we'd need to do a little bit more air handling here to make sure that people are actually typing in numbers but for our example this will be just fine so what we'll do is we'll check to see if our date filter is and then based on that we'll go ahead and use where to filter and just like before we'll say people equals people dot we're and again we need to put in a method here that takes a person as a parameter and returns a true false value now for this I'm going to start out with the short syntax since we're used to it now so I'm going to save P and this will be my parameter and then we're doing comparison based on the start date value of our person object now notice this is strongly typed so we do see P as a person and start date is a parameter on that and we'll just take the year property on that and make sure it's greater than or equal to our start year so this will filter out any items that happen before our start year parameter now since we're takes an ienumerable and returns an ienumerable we can actually chain these together so I can say dot where and we'll say P goes to P dot start date year is less than or equal to the end year and this will make sure that we filter out anything that's greater than that and your parameter that we have coming in now when we start dotting our methods together which is very common when we use a fluent syntax we can see that our lines get pretty long now fortunately there's something that we can do about this in c-sharp the first time I saw this I was a little put out by it but now I'm used to seeing it what we can do is before the dot when we're dotting our methods together we can actually put in line breaks and this is still valid so we have people dot where start date year greater than or equal to start year dot where start date year less than or equal to end year now you might be looking at this and saying Jeremy you really can optimize this and you're exactly right I could actually combine these into a single wear statement and put an and in between our two conditionals and that's what I do in most of my applications but in this case I wanted to show you that we can actually dot these methods together and create chains of linked methods and in fact in this case if we have both of our checkboxes checked we'll have people dot where start date greater than start year we're start date less than n year dot we're first name is equal to what's in our text box and again none of this gets evaluated until we start using this collection now in this case as soon as we assign it to our list box it iterates through that collection and that's the point where all of these methods get run so let's run our application to see what we have now so let's go ahead and just refresh our items and I'll select John Crichton here and if I pick the date filter we can see now we have items between 1985 and 2000 and if I select John we see that we have our three John elements and if I select both we'll see that now we just have two items the items that fulfill both of our conditions and notice that our selected items stayed in place this entire time that's because the selected item that we had was still in our list box each time we filtered our data so this is shown as the basics of figuring out the method signatures of our link methods now that we have this let's keep going in addition to our filtering we also have sorting now if I just unfilter all of our data will see that our items are in no particular order in fact they're just in the order that they're coming out of our library let's go ahead and take a look at our link extension methods and see what we need here so here's a list of our extension methods on ienumerable of T and this time we're going to scroll all the way down to order by and now that we've seen how these methods signatures work it'll be much easier to approach this order by now notice we have two separate generic type parameters here T sors and T key as a reminder T source is the type of our collection so in our case we can replace this with person so where I see ienumerable of T source I can replace that with ienumerable of person so we see by the this keyword that this is an extension method on ienumerable of person which means we can treat it exactly like we traded the where method before and if we look at our other parameter we see it is a funk of TT result but in this case it t source T key now notice this is called key selector rather than predicate like we had in our where statement now if we were to look through the documentation what we would find out is T key is any type that implements the I comparable interface or the I comparable interface depending on what part of the country you're from now all this means is that our object needs to have some concept of greater than or lesser than or before and after now it turns out that most of the built in dotnet types implement the I comparable interface so these are things like integers strings date times those all have the concept of ordering built into them so that means if we want to order based on a string for example all we have to do is return the property that we want and that will be our T key now if we do have a type that does not implement I comparable there is an overload of order by where you can add your own comparison but we won't need to worry about that today because we're going to be filtering based on integers strings and date/time values now one last thing to note about order by instead of returning ienumerable it returns an I ordered enumerable so this is a different interface that still specifies the iteration capabilities of ienumerable but it also has the concept of ordering of the elements so let's go ahead and use order by just like we used our where so instead of having an add filters method I'll create a new method that will add the sorting now this will return and I ordered enumerable of person and we'll call this add sort and it will take an ienumerable of person as a parameter now in our other method we just returned our incoming object as the default state but we can't actually do that here because people is an ienumerable and this is actually expecting an I ordered enumerable as a return value so what that means is we need to come up with a default sort now in our case let's go ahead and sort by the last name so what I'll say is people dot order by and then notice that visual studio is telling us exactly what we need we need a func of person Tiki now we know from reading this that this means we take a person as a parameter and return a Tiki from this particular method so if we had to use a lambda expression we just say P goes to and now we need to figure out what we want to return well by default I just want to sort based on the last name now last name is a string and string does implement I comparable so this is all we need to do so when I say people that order by P goes to P dot last name I've specified that I want you to order this ienumerable of person based on that last name property now to use this method we'll do the same thing that we did with our ad filters so I'm going to wrap the ad filters in the ads sort now this may look strange to you and it actually is pretty strange in fact I wouldn't recommend adding filtering and sorting this way in a real application I'm doing it this way so that we can concentrate on the link and the lambda expressions that we're looking at today the biggest drawback from the way we have things set up is that if we want to filter our values or sort our values we have to repol our data from the library and that's not what we want to do in a production application now if you're curious about how I would implement this in a production application I do have a third project called people viewer dot mvvm and what this has is it has a separate view model to handle all the presentation logic and in that application we don't have to refresh our data if we want to apply filtering or sorting so now that we have this in place let's go ahead and run our application and we should see that we have a default sort based on the last name and in fact that's exactly what we have we see our last names CG H K L M s so we are sorted by the last name in this case so now let's go ahead and hook up our radio buttons so if we go back down to our method we'll start out by saying if the last name sort button is checked then we want to return what we have as our default so we'll just return ordered by last name now if the first names our button is checked now we'll return people order by P goes to P dot first name and again that's another string value now we also have a date sort button so if the date sort button is checked then we want to return people dot order by P goes to P dot start date and start date is a date time value and that obviously has the concept of ordering built into it so let's go ahead and run our application to see what we have right now so we can see we have our last name sort is our default and then if we change it to first name we can see now we have Dante Dave Dylan Issac John John John and if we change it to start date we can see we're sorted by date and I can tell at a glance that's the case because the background colors are actually based on the decade so since the colors are grouped I can tell that we're sorted by date now for the rating item I want to do this a little bit differently because I actually want the highest rated one on top and it turns out that there's a method that we can use for that as well so if the rating sort button is checked then I want to return people dot order by and notice in addition to order by there's also an order by descending so this will sort them in the reverse order so I can say P goes to P dot rating and when we run our application we'll see that if we sort by rating we have nine out of ten stars on the top and four out of ten stars on the bottom so things are looking pretty good for our sorting now there is one other thing about our first-name sorting we have three johns in our collection so what would be nice is if I could do a secondary sort based on the last name property you can see right now we have Koenig Kryten and Sheridan so they're not in any particular order so my first inclination is to do exactly what we did with our where statements so I said where where dot where so I would say order by first name dot order by P goes to P dot last name and if we run our application what we'll see is our output isn't quite what we expect so here we are sorted by last name and if I click on first name notice the sorting didn't change now my first question is did I break the sorting well if we look at start date and rating we see that those still sort appropriately so what actually happened so that our first name sort doesn't seem like it has any effect well it turns out that order by actually does a destructive sort of our data so when we say order by first name dot order by last name that order by last name just completely replaces any sorting that we had before now the problem is if we look at our extension methods on ienumerable we don't see any methods that will help us out but we have to remember that we're actually dealing with I ordered enumerable at this case and it actually does have some extension methods the one that we'll use here is called then by and notice in addition to then by there is also a then by descending then by is a non-destructive secondary sort so this allows us to order by first name then by last name and if we had additional sorts we could say dot then by dot then by so now if we look at our data we'll see that we have our last name sorting and if we click on first name we see that we do have our first name sort back in place and if we look at our John's we'll see they are sorted by last name Kryten Koenig and Sheridan and when we look at all of our functionality together if we look at our selected item for example and add our date filter we'll see that we can combine all of these methods together so what's happening in this case is we're doing our filtering so we're saying we're start date is greater than 1985 and less than 2000 we're ordering by the first name and then we're ordering by the last name so we're actually taking four different link methods and chaining them together to get this particular result so all of these values combined together to create the output that we're looking for so what we've seen by doing this is that link methods really aren't that hard to decipher once we get used to the different parts and we've also seen that visual studio helps us out quite a bit so it will tell us exactly the method signature that we need so for example here it says func of person bool so that tells me right off the bat I need a method that takes a person as a parameter and returns a true false value if we look at our order by statements again we can see that now we have in this case a func of person string now what this actually did is it looked and said you know what the last name property that you're using here is a string so I'm going to go ahead and fill that in for you if we look at our start date will see that it filled it in a little bit differently now if we haven't provided any value at all yet then Visual Studio doesn't know the type that we're using for that T key and so it just tells us T key to let us know we need to fill this in with some type that implements the I comparable interface so now we have a good understanding of link method signatures again the things that we'll see over and over again are ienumerable since these are extension methods on ienumerable of T we will also see generic types and again usually we can replace T source with the type of whatever objects we're dealing with and we also saw that this keyword which tells us this is an extension method that means we can use a little bit of a different syntax when we're interacting with it in our code and of course we spent a lot of time in func and again this is just a built-in delegate type and dotnet and in link methods this tells us where to put our lambda expressions so in our where statement func of T source bool means that our parameter will be whatever type we're dealing with and we need to return a true false value and we see that this basic layout goes into sorting as well so we saw the order by method which also operates on ienumerable and it has a func of T source T key so in this case we need to return some type that implements the I comparable interface and order by descending has exactly the same signature and both of these returned and I ordered enumerable which is something that we can iterate through but also has its own concept of sorting so now that we've seen these link methods in action we should be much more comfortable going through help looking at the different methods that we have available and figuring out how to use them now one common question I do get is how do I use the join method with this fluent syntax and that's something we'll be looking at in a later video but next time we'll be concentrating on the difference between imperative programming and declarative programming and what we'll see is we can use link to do declarative programming where we tell the computer what we want and not how to do it and this can make our code much much more readable until then be sure to visit www.carmensognonvi.com/newsletter
Info
Channel: Jeremy Clark
Views: 23,327
Rating: undefined out of 5
Keywords: Language Integrated Query (Programming Language), C# (Programming Language), Anonymous Function, Lambda Expressions
Id: kFUn8_rdNqM
Channel Id: undefined
Length: 31min 50sec (1910 seconds)
Published: Sun Apr 12 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.