Intro to Yield in C# - What it is, how to use it, and when it is useful

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
the yield keyword in c-sharp can be a confusing one so in this video we're gonna go over what yield is how it works and how to best take advantage of it in our code now this is the first time you've viewed a video on my channel my name is tim corians my goal to make learning c-sharp easier i have hundreds of videos on this channel around c-sharp and the related topics that will probably be helpful to you as well as videos on just having a developer in general and answering those questions in my dev questions series i also have a a site where i sell full courses on iamtimcory.com where i have dozens of courses that will be really relevant to you as well as if you're a c-sharp developer check out all the resources they have there's links in the description for everything also in the description you're going to find a link to the source code for today's video what i do is i package up all a source code i put in a zip file i put a link in the description you fill out a form and i'll email you that source code okay so check that out if you want to get the source code i think that's it let's go ahead and get started with visual studio now we're going to create a new project that is a console application just not really simple we want to get get past all the ui stuff we don't want to care about that we want to focus just a yield keyword and what it is so let's start by getting our our setup out of the way so this is our yield demo app so i'll say yield demo and yield demo app we'll hit net 5 which is the current version as of the creation of this video and we'll go create so it sets up for us our basic starting point just the console application really simple okay so that way we can kind of not focus on this now the yield keyword let's talk about what it does first in abstract or theoretical terms and then let's see an action so in theory what yield does is it allows us to call a method multiple times and have it run for a little bit and then pause and wait for the next call basically keep a stateful um spot in the code can i put his thumb in this in the the index and say hey okay wait wait right there until the next call okay let's flip you know a few more pages put a thumb in and so on that's really you know theoretical it's a little weird so let's see this in action just see how this might work okay let's first start by getting rid of our our sample code i'm going to put a couple of lines in here so console.writeline cw tab tab to create a snippet and we're going to say start of the app and then i'll do another one down here again cw tab tab and where i say end of the app that just gives us some bookends to see okay the app started the app ended and we're going to use these entries as kind of a way to give us an indication of okay this is how the flow of the application is going that's all it's going to do now let's create another class i'll do it in this same file we'll move it off to its own file in a minute or say public class person model and i hit shift enter to get those curly braces to put in if you haven't seen the video i did on the recent 10 tips to make visual studio faster or make you vis faster in visual studio go check that out a couple of videos ago where i cover things like that smart enter or smart line break so in here we're going to say i want a first name and a last name nothing too complex really simple basic demo model okay that's all this class is going to be and we're going to create a constructor out of this so let's do our control dot and say generate constructor again that's the same video i talked about this minute ago and that creates a constructor for us that fills in the first and last name based upon the parameters being passed in i'm also going to add one more thing a console.writeline in here that says initialize user i need to put a a dollar sign in front of us for string interpolation because we'll say uh first name space lasting like so that just lets us know hey you created the person model okay and which person model was it well here's the first and last names you passed in just so we know which model it was okay that's that's our our simple demo person model i'm gonna move that off into its own file okay so now we got the person model class okay now we're getting ready to create our demo for what yield improves upon so let's create another class in here public class let's call this data access that's what it's going to simulate then in here i say public i innumerable control dot to add that using statement um and person model and actually i think i add the wrong using statement it's dot generic there we go and we'll call this gets people okay that's our a really simple method that it's gonna simulate data access but it's not actually data access because we're not actually going to go a database we're just going to create three sample users okay so we'll say a list of person model output equals new like so and then i'll say output dot add new person model will pass in tim and corey all right we'll do this a couple more times now i'd duplicate a couple more times i'm going to say ctrl c ctrl v without anything highlighted and it's going to add two more entries for me in line to duplicate those now for this let's say sue storm and jane smith okay and we're going to say return output okay that's a simple get people method in fact it's so simple that it's not storing anything in this class so let's make it static that we don't need to actually create a instance of data access in order to use it so up here we might say something like var people equals data access dot get people right and then we could do a uh for each on this for each p in people like so and we'll say console writeline and then let's just say our street interpolation here we'll say uh red and then say our p dot first name i suppose spaces around my things but you don't have to peta last name okay so this just says okay get the people and then print out that you've read them okay real simple stuff just to have a demo to start from okay let's run this and see the output all right so we have the start of the app we initialize the user tim corey we initialize sue storm we initialized jane smith we read tim cory we read sue storm we read jane smith and then we ended the app that's the traditional way we normally think of building up our objects and then iterating through them and reading them now what this has done is in this section right here we created all of our objects we put them all into memory we then transmitted that which was just hey here's a pointer to that same spot or a reference to that same list but we we transmitted all those over to the calling method which then read or process all of them in the context of a database maybe we have a list of all the users in address book let's just say there's a thousand of them we would create a thousand user objects and then we would work on those thousand user objects okay that's the standard way we think about doing things but this loads all of these in memory up front and then we do work on them later but only after everything is in memory what yield does is it says maybe there's a better way of doing this maybe you don't need all three of those users or maybe you do but not all at once maybe you need just the first one right up front but maybe you know wait five minutes and then ask for the next one or maybe we're not sure how they're gonna iterate through so why are we creating all of them up front if you aren't going to iterate through any of them so yield says we can do things differently instead of doing all of our initialization up front we will get create the users as you need them and not before so let's see how that work in this code so let's change over our data access code now i do want to say we're up front that yes this is a very contrived simple example at first i'm going to walk you through how to use this in the real world but i want to show you the very simplest i could of yield so instead of having this output variable don't need it instead of having the output.add of course that goes away as well let's get rid of those and we don't need this return down here and we don't need that end parentheses because we're just newing up three different items in front of all of these i'm going to say yield return they may say wait wait tim you can't have three return statements in one in three lines yes you can if you put yield in front of it so what's going to happen is because we say yield return when we call for the first user it will run this line only and then it will wait and then the next time we call for a user user it's going to return this line and the third time it will return this top line and after that it's going to say i don't have any more so it kind of pauses your code mid-stream now notice this is not asynchronous you can have i async enumerable that returns but in general we don't need that unless we're going to be calling asynchronous code inside of this method so i innumerable is fine and yes it's i innumerable not i list or list and the reason why is i innumerable handles the idea of the list the set of items but that might not list the set of items is not necessarily always complete we use innumerable with entity framework because we can do work on a set before we actually do the query well in the same way we're going to be able to look at this set before it's complete so i haven't changed anything else i just changed this code right here say yield return in three spots this code has not changed in the least let me run this same code it all ran but notice the order is a little bit different we have initialize user tim corey and then read tim corey but then we have initialize to storm and red sue storm initialize jane smith and then red jane smith and then end of app so the application does all the same work but the ordering is different that's because what has happened is when we say get people let's actually put a breakpoint right afterwards and run this okay so we're at the break point we have run this lab code but not yet the for each so let's look at that that people list let's go our locals window which is very small i'm going to zoom in here on it all right so this is the people list results view error we don't have a results view no as there's no count it just says current that's all it says in there for there is no current selector yet okay so it's a really different set than we're used to it's not like list instead it actually hasn't even called this code yet in fact let's put a break point right here at the first line which hasn't been called yet i'll prove that in just a minute we run this people let's let's continue running right we're at actually no let's let's skip over so we're going to step into this list and notice that we've now said var p in people and it goes oh i need to call this get people list and it says okay let's yield return and it's going to create that person so it populates that's an automatic step over that's fine it populates the items it's going to spit out that yes i initialized tim corey and then it's going to come back here it's going to go back to the in and it's going to populate this p variable which currently is null it's a little smaller c but it's null and now p actually has let's zoom in here it has a person model with tim cory in it all right so let's put our break points down here just you can see what's happening oops come on there we go i put a breakpoint each line now so now we're going to step into this it's going to print out the console we're going to go to the next four each and say okay the end's gonna run now which means we're gonna run the next to the next yield return statement which is gonna create sue storm now sue storm have been created or initialized now we can go and populate p with sue storm and now the first name here will be sue and the last name will be storm and can print that off and it's going to keep going this way until after the last yield return so you run this it's going to the last deal return and after that so it's going to populate the last person it's going to then populate p is going to go the right line we're going to come back up here and say okay i want you to keep going so where i keep going we get down to this curly brace the end here where it says hey i'm done so it completes this code and then it goes yeah i can't populate that p therefore we're done the for each we go to the end of the application that's the yield keyword in nutshell now i'm going to give you a more concrete example of way to actually use this but i want you a couple at least one more trick before we're done with this simple example so why would you care to have a yield return now this is obviously contrived we would have some kind of code to generate or pull the information from somewhere not just have three yield returns that return three sample pieces of data but why would you do something like this well why would you not just return all of them all at once it seems simpler in fact just so you know this yield return does add a little bit of overhead onto our call essentially keeping a bookmark in a method saying okay i'm going hold on to that state and wait until you call again that takes a little bit of memory so this isn't a free thing we're doing we're actually making it a little more expensive and if we're gonna return the same amount of items it doesn't really make sense but think for a minute what if i didn't do a four each here what if i only wanted a few people or maybe even just one person why would i want three people returned to only use one of them getting more efficient to just return one well we can actually do that using link let's say dot take which you have to add a using system.link take and say you know what i want to take two now if you're familiar with this method um probably you used entity framework before the entity framework uses this but this i concept here is that yeah i want to get people but they only want two of them not three just two i have no clue how many it will return but i'm only going to use two of them well guess what's going to happen when we do this remember that we can make this call it hasn't pre-populated this i enumerable it's just said okay we're ready to run this once you say go ahead we haven't done anything more than that so i say take two i can add that to my i enumerable where it's going to go okay gotcha you only want two therefore i'm not gonna give you more than two so this people now maxes out at two entries even though i have three yield returns let's see what happens if i just run this i initialized tim corey and i read tim corey i initialized through storm i read sue storm and then i ended the app what that means is by just adding this little thing right here take two i have eliminated the creation of a full object that wasn't necessary this is the benefit of yield because i can say i don't want a hundred things i want three and it will only load three into memory so let's see this in a bit more concrete detail so let's move data access right to control dot and move to data access dot cs so you have it for later and i am going to comment out this data access demo okay we're gonna do a new demo now in this demo i'm gonna create a new class for this public class let's call it generators and in here let's create one public static i innumerable control dot to add that using collections.generic notice that it's gone because i actually moved that over with my data access class so innumerable of type int what i call as get prime numbers this is a fun little method what we're going to do is we're going to get prime numbers now you may say well which prime numbers how many prime numbers we're not asking for any of that information in fact we're going to get prime numbers unlimited we're gonna unlimited prime numbers we're not going to limit how many we can get which of course normally would cause a stack overflow exception it won't for us though now in here i create a method that create that finds one or test for one prime number private static bool is prime number int value now this prime number check isn't going to be the most efficient check ever it's not horrible but it's not extremely efficient which is what you'd want for a prime number checker it's going to be going into the tens of thousands but for our purposes this is perfect okay so i just want to have that disclaimer so bool outputs equals true and then 4 i equals 2 it will be i equals 2. i is less than value divided by 2. and we have we got to start with 2 here okay and then in here if value modulus i equals zero if you're not familiar with this does this this percent sign here it's going to divide value by this number and if it divides evenly it'll be zero okay if it doesn't divide evenly it's gonna it's going to return the remainder so in here outputs equals false because it divided by zero it gets zero as the result of of this test that means it has divided evenly therefore is not a prime number that's what the fault is for and we don't need to check any further so we can just go ahead and hit break that's going to break out of the for loop and then we will return output so it does is it's going to loop through all the numbers starting at two going to half of the value and we're gonna check to see if any of them divide evenly okay that's if you wanna go more deep into prime number theory that's topic feeling today but this at least gives us a prime number checker all right now in our get prime numbers i'm going to write code that without yield you should never write right int counter equals one wow this is the kicker right here true if is prime number counter yield return counter and then down here counter plus plus now why should you never write this without a yield well because the while true this is going to run continually forever it will not stop meaning you get a stack overflow out of memory exception you'd have a problem because you would run out of either integers or you don't have memory to hold all the stuff you're doing so this is a problem but because we have a yield return what's going to happen is it's going to say okay return that value and wait to see if i'm called again this means we can run this safely as much as we want now we can't just say 4-h and let run forever because yes that would still cause the same problem we're talking about earlier but we can let it run for as long as we want so let's come here now to our code i'm going to say var prime numbers equals generators dot get prime numbers notice not passing in any other type of modifier there so this i innumerable of type int which i'm saying var here just because i want to type out again that's an i innumerable of type int um i'm just saying get the whole list which again if we can have yield return would be a major problem but it's not it's fine now i can say for each var prime in prime numbers console right line let's just write out the prime itself no reason to go further than that okay now remember i said that yeah you still want to limit this in some way but we've learned how to do that with take two so let's take oh i don't know uh let's start with ten thousand okay and let's run this you might say man ten thousand seems crazy it's already pretty now okay in fact in my testing i found it actually takes longer to print out the numbers than it does to run this so it's pretty crazy but notice that the top prime number here is a hundred and four thousand seven hundred and seven seven hundred seventeen sorry um so this has gone through and found for us ten thousand prime numbers but what it didn't do is run forever it still had an end it's just that we told it when to end which means it didn't generate twenty thousand thirty thousand fifty thousand prime numbers it generated just 10 000. let's get even crazier and say you know what i want to have 10 prime numbers with the same method that i just ran before there's those 10 prime numbers it only generated 10 prime numbers it did not generate an 11th or 12th or 10 000 of them like we just asked for it just generated 10. so we have not used the memory to look for ten thousand or a hundred thousand we've used the memory to look for ten and this is where the yield keyword becomes so very powerful in specific situations not for every situation but with this i can allow the user to generate as many prime numbers as they want because they're not going to say unlimited they're going to have to say yes i want more i could potentially say you know what generate 10 let's generate 10 more let's generate 10 more 10 more and they had to say give me more give me more give me more um they i got a flashback to a grease song um but they only generate 10 at a time they're not generating all of them up front and then only using 10. so that's where the yield keyword can be really helpful so one of the ways this can be helpful is let's say you have a database that has one table that has a million records maybe it's your customer master customer list and you have a page that is going to show all the customers in your database well you can't do that a million records it's just not feasible to load that many records into memory especially since the user isn't going to look through all a million even worse let's say that once you download the records from a database to your application you have to do some work to rehydrate the model may you do some subsequent calls the database or you do some calculations in order to get things like account balances and so on for each user well that'd be very expensive to show a million people when the user wanted to see one or just the first page or if it's help tickets you don't necessarily want to see every help to get in the database you just want to see the one to deal with next the one on the top of the list probably so it doesn't make a whole lot of sense to have every item in that that data grid you just want to show the first page of it which we're used to doing paging operations but this way you could do a paging operation where you pulled the first set from a database you rehydrate and did your work on even a tenth of those show that tenth when i said give me the next page you just rehydrate the next tenth until you get to the end and then you say okay i still need more so i'm going to go back to the database and get the next set and hydrate attend them and send them on the user you can use this in concert with your paging to really hone in on just what you need to do in memory yield is incredibly powerful at allowing you to not know how much you need until you need it so we could be doing this this work right here could be done at run time where i say take 10 now notice let me show you this if i said waiting for user input like so and then let's just do a console readline like so and then afterwards i'm going to do this exact same code actually let's um let's just do like this okay where i get 10 more actually let's make it 15 just so it it's clear that it's different okay so i wait for the user inputs and then i do some more so let's run this we've got the first 10 of them hit enter now i get a next set now since i recalled i called again for the next set it starts over from the beginning which is like okay that's that's not really holding its place you're correct because i did the 10 and i said only give me 10. so i restart on the next call and say okay now just need 15. but if i instead of doing this way if i change this let's change this code right here let's do it a for loop and said 4i 0 less than 10 and then we're going to do is we'll get the next prime number but here's a question how do you iterate over an i innumerable because if we knew its bounds we could say something like you know prime number at position i but that won't work for what we're doing here so this will get a little bit more tricky but i didn't want to show you this because it's an interesting at least thought experiment on how to do this so what we do is we create an iterator so var iterator like so um iterator there you go equals prime numbers dot get enumerator what this will do is it will give us something we can enumerate over enumeration means put numbers to so we're going to iterate over this and use this to identify in this case the next 10. so for i equals 0 i is less than 10. we're not going to care about i we just need to count from 0 and 9 or have 10 of them we're going to say if iterator dot move next well i got red squiggly here that's what comes from an integrator when it's iterator there we go iterator dot move next what it's going to do is notice it's going to wrap in an if statement here it's going to say okay can we move next and if we can let's go ahead and do that now since this is the very first time we run this it's going to move next which really creates goes the first one but we'll see that when it prints out it should print out number one now the move next if it succeeds we're going to say console writeline and in here we can say iterator dot current this is the current number that's on since we've moved next that current number should be the number we're looking for print that out since it did find it else and here we're going to say is just break meaning we can't do any more in the for loop because we're done there is no more ability to move next so this gives us our first 10 we can comment this out we're not going to use the four each they're gonna wait but instead of getting more we can get rid of this line right here and we can run this same code down here notice i didn't grab the iterator again we're going to use the same iterator and we're going to take off this take 10. so now it's going to get unlimited number of prime numbers but we're going to iterate over it 10 here and we'll do 15 here just to show we can it'll move next and iterate over them let's run this and see what happens we have number one start with number one great 1 through 19 that's the first 10 prime numbers hit enter now we have 23 through 83 that's the next 15 prime numbers and we're done this is how we could use our application to say okay user you want the first 10 cool i'll give you the first 10. they say oh i want more cool i'll get more for you and more for you forever potentially so i want to show off you can ask for it more than once if you set it up properly if you go back and and redo the call that will restart that operation which is why the for each we had two different calls to the same method that does the yield didn't work the way you would first expect it to okay so that's how i do that but what if we decide we want to have a list because everyone likes lists right i love the list so let's do this let's um let's comment out well actually let's just comment out this one down here so we just have this commented out i'll leave it for you for later where i'll loop through just 10 but just for safety's sake what i'm going to do is actually i'm going to comment this out as well and we're going to go back to our 4-h all right which does mean we have to limit this and there's an important point for this so take nothing not the enumerator that should be commented out as well no need for that we're going to say dot take and let's take 30 000. that's a lot of prime numbers and when you run this app on your computer it may not run at the same speed mine does so you may want to lower that number but i know that mine doesn't take a ton of time with this but it does take a little bit of time okay i've asked for 30 000 then we're going to loop over it all right and we're going to run this and it's already scrolled i mean it's already going it'll take a little bit but it's going to print off all 30 000 prime numbers note we're not going to reach the number thirty thousand we've already seen that by far we're going to print out thirty thousand prime numbers and they get further and further apart as you go higher the numbers so it's three hundred and fifty thousand uh 347 is our top prime number so but you saw how that ran actually the printing off the console is a very expensive process which is why it took as long as it did but i want to show you something let's just say you go cool i i like this but i really want to list i want to generate a list of these so i can work with the list keyword and and have all the extras that list provides this is a mistake when dealing with yield i'm going to show you why let's run this app again notice it says start of the app and nothing seems to happen it's sitting there and waiting and waiting and waiting what's happening well what happened is it actually generated all of those values and then started printing them so it it generated up through prime number 350 347 before it printed number one because the to list what it does is it says in order to be able to do all the cool stuff list does i need to know things like the count so i have to populate this entire i innumerable with all 30 000 elements before i go on to this line right here so keep that in mind when doing the yield is that when you say two lists on your i enumerable it immediately calls everything so if i didn't have a take 30 000 here this would do a two list on get prime numbers which remember get prime numbers has no end which means it's going to try and get a list of every possible prime number to the end of the universe which is going to obviously stop before then not your computer will tell you that because your computer is going to crash at some point it's going to say i'm either out of memory or i've reached the end of int 32 which is a big number so either way you're going to have a problem so you do not want to use two lists on your i enumerable it's the same reason why you don't return a list of int you return i innumerable so just keep that in mind and if you're thinking hey i've i've done some of this link stuff with entity framework and i use two lists all the time that's a problem because the the i innumerable allows you to do work on it before you do the query once you say to list you have gone to the database and done the query and then anything after that is done in memory and that can be a very expensive process so be careful where you put this to list if anywhere in your entity framework calls okay so that's just a a bonus tip there so this is the yield keyword yes it does have limitations yes it's not something you use every day but when you find the occasion where you say hey maybe just get prime numbers the the example you're going to use but whatever it is we say you know what i need to do some work and it's expensive work but i don't know how many times i'm going to need it how many times the user's actually going to want me to do that work yield can be a really powerful solution in your toolbox where you say you know what i don't care as many times user wants to do it we're going to do that and we'll just use the yield keyword to not do the work until they request it that way we're only doing just enough to satisfy a user and no more this can make for a very efficient program and more than makes up for the little extra overhead that yield adds when you're dealing with that placeholder bookmark that's holding on to okay so that's the yield keyword i'll give you this source code the link's down the description below um check it out try it out definitely practice this because it takes a little bit to make sure you get your brain wrapped around what it's doing why it's doing it use the break points like i did walk through it be careful on not limiting i would encourage you to first start using yield just limit things even if you think that's way beyond you'll ever use put a limit on it that way if you accidentally have to list you don't blow things up and cause massive problems but just try us out get your hands dirty with this create a few practice projects that mimic what i did or close to it with a few different tweaks try it out with databases try it out with other expensive operations that you do and just make sure you understand how it works so that when it comes time to use in production you already have experience in it all right let me know if you have any questions down in the comments let me know if you have used yield in any way in your production code i love to hear about it thanks for watching and as always i am tim cory [Music] [Applause] you
Info
Channel: IAmTimCorey
Views: 64,075
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, training, how to, tim corey, C# training, C# tutorial, .net core, yield, c# yield, yield return, yield in c#, yield return statement, c# yield return, yield keyword c#, yield return ienumerable
Id: AAz8q6dOCYk
Channel Id: undefined
Length: 43min 58sec (2638 seconds)
Published: Mon Jul 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.