C# Delegates Explained || +Func +Action +Closure

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
delegates represent a functional programming paradigm known as function as a value and you're using it whether you're aware of it or not and if you're not using it you most certainly rely on it in one way or another that's why i think it's important to know the concept behind it and then secondary the syntax in c-sharp so you can actually write the thing i know some programmers fail to see the value behind it so hopefully today i will be able to relay to you why delegates or functions as values are valuable and then we're gonna take a look at some behind the scenes of the delegates in order to understand potential overheads and a bit closer to what they actually are so let's dig in let's begin with explaining the the idea behind the function as a value so how you usually store descriptions so i'm a human being right that's a description uh i have a long hair and a black t-shirt so those are objects you can classify them as fields and you store a color like black and a variable how about instead of descriptions we go ahead and store functionality doing something like running or taking things out of the box and putting them into a bigger box why can that not be a variable well that's precisely what it is it's basically taking functions and putting them on the same level as normal variables okay why is that useful let's say i am going to the beach many people go to the beach and when i go to the beach i like to drink water who am i kidding i drink beer right some people drink water i drink beer kids drink lemonade okay so there's three things we can consume on a beach let's go ahead and write this up first i'm gonna write up the three beverages that you can drink so public avoid drink water and i know this is a really simple example if you're looking at this this doesn't make sense i can write it like this imagine that this is a more costly operation than rather than just printing a string okay try not to fight the example try to understand the concept behind it and that you can substitute the drinking or rather printing of a string by any by anything else okay so drinking water and if you're also wondering what is this uh ide i'm using this is called linkpad and this is not really an id this is like a sketchpad a script uh you basically write c sharp scripts with it kind of like you do in python and it's just a really neat way to quickly show concepts or proof of concepts and stuff like that or write up scripts so that you can reuse right anyway link in the description at the moment we're just printing out stuff right so drinking lemonade here we're going to be drinking beer let's move this over and if you're wondering about what the dump method does what it does is essentially just outputs stuff to the right side here okay so let's go ahead i'll put this a couple of times we're going to be drinking water drinking beer and we're going to be drinking lemonade right so there is three things we can do okay again if you're struggling with the example that we're just outputting a string imagine you have an entity and you're saving it to a database you may be saving it to redis cash store you may be saving it to an sql store you may be saving it to document storage each one of those is gonna look differently imagine these are this is a storage operation if you'd like but for now we're gonna keep it simple now let's put myself in a scenario where i'm going to be present somewhere or doing something and i spelled beach wrong okay so i'm relaxing on the beach again uh let's say i just want to be relaxing on the beach some people they relax on the beach and drink water which is where we're going to drink water some people are going to be relaxing on the beach and drink beer okay and hopefully you see the point here four functions just to sort of output this and you know drink some water and again if you i'm not i'm going to stop this is the last time i'm mentioning if you're like well we can put a string and just dump the string here if it's not no imagine this is a bit of a more complex operation okay uh let's go ahead and do something a little bit more different the first thing that i'm going to lead up to i'm going to do a little detour before going jumping into delegate syntax straight away i'm going to expose what they are first as a single method interfaces as a way to think about them let's do this let's create a public interface and we'll call it i drink so we might do something like have a little drink function here okay and we do public class and drink water and i'll just put o here for object right and this is going to inherit from my drink very verbose a lot of things yeah let's go ahead and drink water and then i can do the same thing for other methods hopefully you get the picture here so we're getting this explosion of classes here if we want to do it so drink water drink beer again but what we get with this implementation let's actually follow through with it i think it will be worth seeing this transformation water lemonade and perhaps what we can do is maybe point to these things i think i don't think we'll will we i don't yeah we won't be able to grab our skull as me just meter ping around but uh yeah so we got these objects now so what we can do now is we can delete these specific implementations and we can pass an i drink interface and what we can do is well if drink doesn't equal null uh let's go ahead and you know drink the drink cool so now whenever we're gonna go and relax on the beach we can um you know what which object do we want we can either pass null and then we're not going to drink anything just forgot the semicolon there let me comment this stuff out uh we can create a new drink water object okay and that's kind of what a delegate is but at the moment what we're doing is we have to create an object for each one of these and define an interface to be able to substitute what action or what thing we want to do so the thing that we want to do is hiding in a inside an object okay delegates functions as values are still those same objects although an object is kind of misleading way because the object exists purely for the existence of this function okay so all this this this thing right here that i'm gonna like move out this is the important stuff that i'm highlighting this gunk this class we don't need to know about we don't need to know about this thing right here so all of this is just it's nothing we don't need to know this okay what's important is the thing that we're trying to do the class around it it's just a place that holds it it doesn't add value to like the reading of the code and this is partly what it what it's about it's about readability and intention so we now come up with a syntax of delegates where it's important to understand the syntax if you're struggling with the syntax of delegates it's important to understand what a signature is a signature of a function i'm gonna explain that to you okay so drinking action we're going to define it and this is going to look let me cut it let me bring back all my objects and i'll just put it here this is a signature this is what a signature is a function it's the return type and the parameters that is what allows you to align functions okay to align functions if a function has the same form and the form is having a identical signature so void and zero parameters same signature void no parameters same signature the name doesn't matter so much it's all about the return type and the parameters okay that is what's called the signature as long as these match you can fit this interface okay you can think another way you see the thing that we define here this is what you're defining here without an interface so the delegate is the method on the i drink interface and that's what c sharp gives you behind the scenes which we'll explore in a second and then it also gives you this this object in which case you just need to provide its implementation sort of thing so now that we understand that this delegate the thing the interface for a function that we define here it's just this thing here we can go ahead i'll remove this again and we'll say okay we are expecting this interface here so instead of this object i'll just make this public real quick okay so instead of the object we will need to put in a function i think we do so instead of calling remember if we call a function we're really evaluating it to void okay so what we have to do is we have to pass the actual function see how we're not calling we're not putting braces there in order to invoke the function we have we put it here okay so once we have the drink we can just go ahead and call it like this all right so you can see how much less syntax we have and we can go and relax on the beach and drink specific things okay and we can go and ahead and be on the beach and drink lemonade we can do all of these things and if we go ahead and we wanna you know run running 10 miles we want to go ahead and you know run and drink beer we can do that as well so you can see how we are the the reusability of code is like marginally increasing it's skyrocketing without actually having to introduce a lot of code ourselves and this is what delegates do they're gonna shrink your code base and they're gonna give you more readability the less you have to read the quicker you can understand your code okay now let's take a look at two kids of delegates funk and action and we'll take a look at how we can use those and actually before we do this struck an idea just struck me it's probably worth showing that what we can do is we can actually just say var drinking action so a variable will equal a new drinking action okay and the constructor itself will take a parameter of the action right so we're literally creating the interface kind of thing and then what we can do is we can say drinking action and just invoke this function okay so this would create the container in which the function goes all right now we can kind of recognize that it's an object that just sort of contains the implementation and that the primary primary usage of it is readability and reuse of code we can now take a look at funk and action so funk will be really easy to understand once you get it let's take a simple example of adding two things so we say we want to add and this will be actually i'm kind of going to be introducing lambdas here i think it will be okay if we learn about lambdas here as well so let's say a plus b so if we call add one plus one we dump it we're gonna get to indian okay so let's go ahead and just comment this stuff out here and drinking action as well we don't really need it you can see the two being printed i'm gonna go ahead press f12 here so i want to take a look at what a funk is and as soon as this pops up there we go hopefully you can see this can i zoom in that's a search uh i'm afraid i can't do much but hopefully you can read this delegate to your result funk and this is really where you're going to get it no generics if you don't i'm sorry i'll make a tutorial on generics as well but the signature is t result it's kind of defined here and then the arguments are t1 and t2 a funk is just a generic delegate okay and the same for an action but the primary difference between a func and an action sorry let's say we'll put int here and we're going to say print number equals what we say we supply a number and then we just go ahead and dump it okay so let me just put this down on a new line here again action is not a break point we're going to take a look at what an action is and an action is again it's just a generic delegate the main difference between funk and action is funk as a return type okay so func a function has to return something an action is a delegate that's void so it doesn't have to return anything its signature starts with void and then all it is just parameters as you could probably imagine uh defining your delegate like this and then having it basically if i have this in another file let's simulate that by putting it up here if i look at this i don't know the signature of the function i don't know what it does so i have to go to this function and i have to take a look at it okay what we can do is because the signature is void to start with we're going to use an action we can go ahead and say action and it supplies no parameters so we don't have to specify a generic type and this is all still valid code which we can trigger okay if we want an action that takes parameters we then specify an integer if we want to add more parameters we will have to kind of wrap it like this but hopefully you get the picture this represents this integer this represents this integer so the definition is kind of in your face i can say okay so instead of having just the name of drinking action action is actually just a function that returns void and no parameters if we go ahead and supply something like a function a func integer here that returns an integer i already know this is a delegate that takes no parameters and returns an integer okay and again just understand function action are both just delegates now let's talk a little bit about lambdas because some people think lambdas and delegates are kind of the same thing and on the high level if you ever get asked somebody asks you what's a lambda you tell them it's high level definition it's an anonymous function same way as a delegate this function as a value you do not start describing that it's a container for it and so on and so forth you give the high level definition if they ask you to go lower you go lower this is where we're gonna go lower because uh if you're sticking around this fighting video you're probably interested right so let's find out delegates right so these things and lambdas are separate things okay lambda is one of these one of these guys it's a function delegate represents a function okay in reality delegate is a container in which the function goes and if that doesn't kind of paint a clear enough picture for you we're gonna go into a different example here and here i'm going to try to show it to you through inspecting of intermediate language code and stuff like that let's go ahead and bring up a let's actually define our own delegate because that's going to be a little bit more visible we're going to say integer and get number so then get number get n equals no value or rather maybe parameter list we'll see what that goes yeah so we're not going to be discarding parameters it's just going to be an empty parameter less call okay and then we can go ahead and call this and i mean i don't there we go printing out a five right nothing special let's dissect this let's find out what's going on there under the hood i'm gonna bust out a l here and i'm gonna try to commentate this uh as best as i can from what i remember of what these op codes are when i was uh trying to understand this myself and what i'm what else i'm gonna do if you're using linkpad you can press alt shift r for fully compilation that's what i'm just gonna press now and we're gonna take a look at uh the actual module here that is being spat out and uh hopefully i can convey the knowledge to you so it's okay to drop off here if th this is of little value when you're actually using delegates other than maybe performance reasons but that's not what the way they exist they exist to increase your readability okay so here we have the main function which is pretty much the representation here right which is kind of like what this whole thing is let's go to the get number so this is a delegate this is the definition for the delegate that we created base types doesn't matter so much this is the constructor for it so i want you to pay attention here we pass an object to it and an integer pointer so back when i was showing to you the interface object representation that's kind of what it is but not really i'm gonna show you a little bit of a closer look to it in a minute after we get done with this and hopefully at that point it will paint more paint a more clearer picture of what they are so then we have uh begin invoke and end invoke these two are for if your delegate is asynchronous and then invoke which is just call the function okay then we have this object here okay this object is quite interesting it looks a little bit funky and once you unpack it if you understand what it is but let's step through this one by one so we have a class a static field with which basically initializes itself so the it's a singleton and then we have the get number delegate here okay and then we have a function here so if we expand it this is the function that we've defined so this is this lambda so even though this lambda contains the delegate i want you to understand that this class just represents the lambda the reason the delegate is there so we don't have to create it again so it's sort of caching itself okay and we'll see how this cache works through looking at this so lds field is we basically take the value of 9 underscore four which is this field and we pop it up we put it onto the stack we then go ahead and br true which does something along the lines of if if not null jump to this label here so it's going to jump there so this is where i said it's about caching it's about checking is this already initialized if it is we can skip the initialization process and just go to using it so here we would skip although at the beginning it's not initialized so we take the value off we then go ahead and get ourselves the object and then we get ourselves the function here okay so here we get a field here we get a pointer these are specific uh instructions i mean you can look them up as well and then what we do is we go ahead and we invoke the constructor on the delegate okay so the lambda as an object gets passed into there as where as well as a pointer to the function so this is where we invoke this constructor where the object of the c and the function which is the main function in here gets passed into the into there so the pointer of it back we're gonna get a pointer to the delegate and we're gonna go ahead and set it to the field so then where we go ahead and initialize this field here so this is all happening under the covers super simple stuff as the alaka whatever whatever in interests of time we're gonna go ahead and uh just then call invoke on the object that was uh or whatever got allocated onto the stack here at what's called local variable index zero then we get the local variable i i like how i say in the interest of time and then keep rambling on and then go ahead and explain myself why i it didn't do take the shortcut whatever let's go call virtual invoke we call invoke and then we go ahead and call dump and whatever those things do okay so if you didn't understand any of that let's go ahead and i'm going to try to sort of reel it back into i will not be able to use the end pointer there because that's kind of an instruction on the op code level i will instead use a method information so to paint it a little bit more simply we're going to create my delegate which is going to have a public constructor okay my delegate we're not gonna put anything in it just yet we're also going to have a my lambda like that and what my lambda is going to do is it's going to have this definition here so public and main is what the function was given and we're going to say five so this also for some reason uh well for caching reasons not some reason holds my delegate so my delegate just like that and that's going to be null uh so in here what are we doing here we pass an object and we pass a pointer so i'm gonna opt in for method info like that let me go ahead and drop this down a little bit as you can see it and then i'm going to do maybe is this writer level integration it is not let's go ahead and put this something like this here method info and info here and then we can do obj equals obj and then we can have info equals info and then we can have our trusty old signature that we define here and invoke and here we go ahead and invoke the info invoke so we pass it along here and we also pass the object into here it's also going to have some parameters which we don't have like guys let me just uh conversion oh yeah and obviously i gotta do something like that this is essentially what it is so what we don't see is we don't see this these bits here on the delegate implementation so again if i quickly open this up so in here once we get to the get number so this is our delegate you can see how if we look at the delegate itself we don't see the implementation and that is because it's given to it by the run time it is not defined at compile time so right now we don't know we don't know what it is until it runs okay and this is kind of what it looks like although this is replaced with a pointer and some quite a similar implementation so let's go what happens here is we instantiate the my lambda so my lambda l just like that we do a little check if l my delegate equals null okay if it is no uh let's go ahead and do the following we're going to create a my deli new my delegate and in there we're going to do something along the lines of pass the object into it and then also what we're going to do get a type of uh my lambda here and we're gonna get a method that you know is called the main and let me drop this down on new lines here hopefully i don't know if this adds readability or not but there we go we have the delegate we then go ahead and assign it to the my delegate on the uh object itself and the point that i'm trying to demonstrate here it again it's not it's not important to know this actual implementation but the important thing to note here is this is the gymnastics that happens in the background in order for you to have a more comfortable more readable programming model okay it's for you to be able to read and understand more quickly once you need performance get rid of it okay because performance code is this this is right here this is not readable but that's what you write in the end okay to make it performant but anyway let's go ahead and finish this off so we can go ahead on the my delegate we can invoke it and we can go ahead and dump it all right and let's take a look at the result and the result is still still five and that is pretty much what goes on under the covers if you are interested in the particular thing that actually happens to the get number delegate object that is going to be here right so you can see the extern k word so it's some external implementation essentially this is usually also used when you provide an implementation in a separate dll an external dll or basically you have c plus loss code compiled to a dll and then you define its interface and see sharp code uh let's uh i i wanted to show what's kind of like where does the delegate inherit from so if we have a get number delegate so let's go ahead and bring it down here get number we can go ahead and have some functions on it okay and you will see that it inherits from this delegate type i don't know if we'll be able to see its uh child childhood type it's basically two classes system.delegate that it inherits from and if we take a look at it we can see basically like a bunch a bunch of stuff inside of here taking a look through all of it is it important not really can you inherit from this class no it's a special kind of class that is used as an implementation for your delegates you also get a multicast delegate all right and again this is just another class which is used to implement the delegate that you define and again you are not allowed to use this class for you know define your cons custom implementations of delegates so one last important thing to explain to you is a closure and it will be so much easier to see because you know all this stuff about delegates now and to understand what a closure is all right we're going to come back to this example and what we're going to do is we're going to take integer i we're gonna give it a five and then we're going to go ahead and add i alright pretty cool so this is an object and to this object we're going to be assigning a five uh we can run this we can take it look at the al code so you can see how we're it's if if this was something like a static function okay you can see it's being underlined here this is kind of like if we had public and i5 here it says play plus i if we define this to be static we can no longer use this here right so in this manner uh all lambdas and delegates are they take away the need for you to create this uh bulkiness of classes and interfaces it does it for you all right so hopefully you understand that closure is this specific thing it's like putting your variable inside of that function so let's go ahead and take a look at what the code behind looks like i'm going to go ahead and get this thing right here so let's take a look at the class and you can see that the i field becomes part of the class and this is pretty much what a closure is so if you ever hear someone using words like closure now you know what they're talking about essentially adding some kind of value to the scope of the object where the function is being performed all right this will be it for this video thank you very much for watching hopefully you enjoyed it if you did like subscribe if you have any questions as always leave them in the comments section come ask them on my discord server any other c sharp specific topics you'd like me to cover please tell me i also stream on wednesdays and sundays make sure to come join for the big lols that's where it happens hopefully i'll see in my other videos
Info
Channel: Raw Coding
Views: 12,909
Rating: undefined out of 5
Keywords: c#, delegate, Action, Func, tutorial, explained, syntax, functional programming, guide, example, closure, csharp
Id: KaxNwGA9fiY
Channel Id: undefined
Length: 32min 42sec (1962 seconds)
Published: Mon Jan 25 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.